summaryrefslogtreecommitdiff
path: root/audio
diff options
context:
space:
mode:
authorDipannita Shaw <[email protected]>2021-04-27 14:26:21 -0700
committerDipannita Shaw <[email protected]>2021-04-27 14:26:21 -0700
commit78a1795995814a0bac43042f7ca68e83ab525bd5 (patch)
tree8e2eb0e8c3a11220f2f119964c6c6e3674eda0da /audio
parent465e27457dd3b47cf64e4b7274705cc6acc011a6 (diff)
parent672fafbcc455cd97172b2df78040c7c405e32d00 (diff)
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'audio')
-rw-r--r--audio/simpleaudiosample/Package/package.VcxProj128
-rw-r--r--audio/simpleaudiosample/Package/package.VcxProj.Filters21
-rw-r--r--audio/simpleaudiosample/README.md133
-rw-r--r--audio/simpleaudiosample/SimpleAudioSample.sln113
-rw-r--r--audio/simpleaudiosample/Source/Filters/Filters.vcxproj282
-rw-r--r--audio/simpleaudiosample/Source/Filters/Filters.vcxproj.Filters27
-rw-r--r--audio/simpleaudiosample/Source/Filters/micarray1toptable.h210
-rw-r--r--audio/simpleaudiosample/Source/Filters/micarraytopo.cpp825
-rw-r--r--audio/simpleaudiosample/Source/Filters/micarraytopo.h97
-rw-r--r--audio/simpleaudiosample/Source/Filters/micarraywavtable.h292
-rw-r--r--audio/simpleaudiosample/Source/Filters/minipairs.h177
-rw-r--r--audio/simpleaudiosample/Source/Filters/speakertopo.cpp118
-rw-r--r--audio/simpleaudiosample/Source/Filters/speakertopo.h22
-rw-r--r--audio/simpleaudiosample/Source/Filters/speakertoptable.h206
-rw-r--r--audio/simpleaudiosample/Source/Filters/speakerwavtable.h (renamed from audio/sysvad/PhoneAudioSample/FMWavTable.h)152
-rw-r--r--audio/simpleaudiosample/Source/Inc/Inc.vcxproj260
-rw-r--r--audio/simpleaudiosample/Source/Inc/Inc.vcxproj.Filters27
-rw-r--r--audio/simpleaudiosample/Source/Inc/NewDelete.h104
-rw-r--r--audio/simpleaudiosample/Source/Inc/basetopo.h96
-rw-r--r--audio/simpleaudiosample/Source/Inc/common.h477
-rw-r--r--audio/simpleaudiosample/Source/Inc/definitions.h198
-rw-r--r--audio/simpleaudiosample/Source/Inc/endpoints.h133
-rw-r--r--audio/simpleaudiosample/Source/Inc/kshelper.h159
-rw-r--r--audio/simpleaudiosample/Source/Inc/mintopo.h81
-rw-r--r--audio/simpleaudiosample/Source/Main/Main.vcxproj (renamed from audio/sysvad/PhoneAudioSample/PhoneAudioSample.vcxproj)205
-rw-r--r--audio/simpleaudiosample/Source/Main/Main.vcxproj.Filters44
-rw-r--r--audio/simpleaudiosample/Source/Main/NewDelete.cpp141
-rw-r--r--audio/simpleaudiosample/Source/Main/SimpleAudioSample.inxbin0 -> 15164 bytes
-rw-r--r--audio/simpleaudiosample/Source/Main/SimpleAudioSample.rc (renamed from audio/sysvad/PhoneAudioSample/PhoneAudioSample.rc)10
-rw-r--r--audio/simpleaudiosample/Source/Main/adapter.cpp844
-rw-r--r--audio/simpleaudiosample/Source/Main/basetopo.cpp688
-rw-r--r--audio/simpleaudiosample/Source/Main/common.cpp2772
-rw-r--r--audio/simpleaudiosample/Source/Main/mintopo.cpp (renamed from audio/sysvad/PhoneAudioSample/handsetspeakertopo.cpp)170
-rw-r--r--audio/simpleaudiosample/Source/Main/minwavert.cpp1683
-rw-r--r--audio/simpleaudiosample/Source/Main/minwavert.h302
-rw-r--r--audio/simpleaudiosample/Source/Main/minwavertstream.cpp1644
-rw-r--r--audio/simpleaudiosample/Source/Main/minwavertstream.h248
-rw-r--r--audio/simpleaudiosample/Source/Utilities/ToneGenerator.cpp285
-rw-r--r--audio/simpleaudiosample/Source/Utilities/ToneGenerator.h74
-rw-r--r--audio/simpleaudiosample/Source/Utilities/Utilities.vcxproj284
-rw-r--r--audio/simpleaudiosample/Source/Utilities/Utilities.vcxproj.Filters (renamed from audio/sysvad/PhoneAudioSample/PhoneAudioSample.vcxproj.Filters)23
-rw-r--r--audio/simpleaudiosample/Source/Utilities/hw.cpp446
-rw-r--r--audio/simpleaudiosample/Source/Utilities/hw.h105
-rw-r--r--audio/simpleaudiosample/Source/Utilities/kshelper.cpp958
-rw-r--r--audio/simpleaudiosample/Source/Utilities/savedata.cpp1033
-rw-r--r--audio/simpleaudiosample/Source/Utilities/savedata.h189
-rw-r--r--audio/sysvad/EndpointsCommon/EndpointsCommon.vcxproj18
-rw-r--r--audio/sysvad/EndpointsCommon/mintopo.cpp3
-rw-r--r--audio/sysvad/EndpointsCommon/mintopo.h18
-rw-r--r--audio/sysvad/EndpointsCommon/minwavertstream.cpp4
-rw-r--r--audio/sysvad/EndpointsCommon/speakertopo.cpp1
-rw-r--r--audio/sysvad/EndpointsCommon/speakertoptable.h13
-rw-r--r--audio/sysvad/Package/package.VcxProj37
-rw-r--r--audio/sysvad/PhoneAudioSample/CellularWave.cpp685
-rw-r--r--audio/sysvad/PhoneAudioSample/CellularWave.h126
-rw-r--r--audio/sysvad/PhoneAudioSample/Cellulartopo.cpp1117
-rw-r--r--audio/sysvad/PhoneAudioSample/Cellulartopo.h184
-rw-r--r--audio/sysvad/PhoneAudioSample/Cellulartoptable.h267
-rw-r--r--audio/sysvad/PhoneAudioSample/Cellularwavtable.h286
-rw-r--r--audio/sysvad/PhoneAudioSample/FMTopTable.h199
-rw-r--r--audio/sysvad/PhoneAudioSample/FMTopo.cpp985
-rw-r--r--audio/sysvad/PhoneAudioSample/FMTopo.h152
-rw-r--r--audio/sysvad/PhoneAudioSample/FMWave.cpp389
-rw-r--r--audio/sysvad/PhoneAudioSample/FMWave.h84
-rw-r--r--audio/sysvad/PhoneAudioSample/handsetmictopo.cpp274
-rw-r--r--audio/sysvad/PhoneAudioSample/handsetmictopo.h21
-rw-r--r--audio/sysvad/PhoneAudioSample/handsetmictoptable.h245
-rw-r--r--audio/sysvad/PhoneAudioSample/handsetmicwavtable.h447
-rw-r--r--audio/sysvad/PhoneAudioSample/handsetspeakertopo.h86
-rw-r--r--audio/sysvad/PhoneAudioSample/handsetspeakertoptable.h156
-rw-r--r--audio/sysvad/PhoneAudioSample/handsetspeakerwavtable.h550
-rw-r--r--audio/sysvad/PhoneAudioSample/michstopo.cpp275
-rw-r--r--audio/sysvad/PhoneAudioSample/michstopo.h21
-rw-r--r--audio/sysvad/PhoneAudioSample/michstoptable.h257
-rw-r--r--audio/sysvad/PhoneAudioSample/michswavtable.h447
-rw-r--r--audio/sysvad/PhoneAudioSample/minipairs.h602
-rw-r--r--audio/sysvad/PhoneAudioSample/phoneaudiosample.inxbin45990 -> 0 bytes
-rw-r--r--audio/sysvad/PhoneAudioSample/speakerhstopo.cpp275
-rw-r--r--audio/sysvad/PhoneAudioSample/speakerhstopo.h21
-rw-r--r--audio/sysvad/PhoneAudioSample/speakerhstoptable.h168
-rw-r--r--audio/sysvad/PhoneAudioSample/speakerhswavtable.h755
-rw-r--r--audio/sysvad/README.md176
-rw-r--r--audio/sysvad/TabletAudioSample/ComponentizedApoSample.inxbin18736 -> 18770 bytes
-rw-r--r--audio/sysvad/TabletAudioSample/ComponentizedAudioSample.inxbin50422 -> 50506 bytes
-rw-r--r--audio/sysvad/TabletAudioSample/ComponentizedAudioSampleExtension.inxbin11338 -> 11262 bytes
-rw-r--r--audio/sysvad/TabletAudioSample/TabletAudioSample.vcxproj20
-rw-r--r--audio/sysvad/TabletAudioSample/tabletaudiosample.inxbin72830 -> 72864 bytes
-rw-r--r--audio/sysvad/adapter.cpp2
-rw-r--r--audio/sysvad/common.cpp6
-rw-r--r--audio/sysvad/common.h3
-rw-r--r--audio/sysvad/sysvad.sln22
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/APODeviceTest.cpp1120
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/APODeviceTest.h180
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/APOOSUpgradeTest.cpp96
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/APOOSUpgradeTest.h38
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/APOStressTest.cpp777
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/APOStressTest.h50
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/CAPXHelper.cpp247
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/CAPXHelper.h33
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/CAPXLoggingFrameworkTests.cpp160
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/CAPXLoggingFrameworkTests.h73
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/CAPXNotificationFrameworkTests.cpp168
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/CAPXNotificationFrameworkTests.h84
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/CAPXThreadingFrameworkTests.cpp118
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/CAPXThreadingFrameworkTests.h73
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/FormatHelpers.h330
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/TestEffectsList.cpp225
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/TestMediaType.cpp227
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/TestMediaType.h163
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/TestWasapiUseFromAudioDg.cpp244
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/Wrappers.h121
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/audioconnectionutil.h129
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/sinewave.h60
-rw-r--r--audio/tests/HLK/ThirdPartyApoTests/stdafx.h123
-rw-r--r--audio/tests/KSPosTst/KsPosTestTaef.cpp215
-rw-r--r--audio/tests/KSPosTst/PreComp.h108
-rw-r--r--audio/tests/KSPosTst/TestResourceBuild.cpp522
-rw-r--r--audio/tests/KSPosTst/locallimits.h25
-rw-r--r--audio/tests/KSPosTst/pintest.cpp518
-rw-r--r--audio/tests/KSPosTst/tests.h18
-rw-r--r--audio/tests/KSPosTst/timetest.cpp50
-rw-r--r--audio/tests/PinResourceHelpers/HalfApp.cpp (renamed from audio/tests/wavetest/HalfApp.cpp)73
-rw-r--r--audio/tests/PinResourceHelpers/PreComp.h143
-rw-r--r--audio/tests/PinResourceHelpers/PropertyHelper.cpp (renamed from audio/tests/wavetest/PropertyHelper.cpp)172
-rw-r--r--audio/tests/PinResourceHelpers/TestResource.cpp (renamed from audio/tests/wavetest/TestResource.cpp)6
-rw-r--r--audio/tests/PinResourceHelpers/TestResourceHelper.h (renamed from audio/tests/wavetest/TestResourceHelper.h)4
-rw-r--r--audio/tests/wavetest/HalfApp.h195
-rw-r--r--audio/tests/wavetest/PreComp.h107
-rw-r--r--audio/tests/wavetest/PropertyHelper.h190
-rw-r--r--audio/tests/wavetest/TestResource.h66
-rw-r--r--audio/tests/wavetest/TestResourceBuild.cpp55
-rw-r--r--audio/tests/wavetest/WaveTestTaef.cpp6
-rw-r--r--audio/tests/wavetest/WaveTestTaef.h5
-rw-r--r--audio/tests/wavetest/comptest.cpp15
-rw-r--r--audio/tests/wavetest/tests.h2
135 files changed, 23142 insertions, 10075 deletions
diff --git a/audio/simpleaudiosample/Package/package.VcxProj b/audio/simpleaudiosample/Package/package.VcxProj
new file mode 100644
index 00000000..a70e4820
--- /dev/null
+++ b/audio/simpleaudiosample/Package/package.VcxProj
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|ARM64">
+ <Configuration>Debug</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|ARM64">
+ <Configuration>Release</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Source\Main\Main.vcxproj">
+ <Project>{E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <PropertyGroup Label="PropertySheets">
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Utility</ConfigurationType>
+ <DriverType>Package</DriverType>
+ <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
+ <Configuration>Debug</Configuration>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{830B14D5-0E32-4F9E-AEFA-4C9F6FC13C2A}</ProjectGuid>
+ <SampleGuid>{E9D167E6-E633-4284-8F02-FF86DF3B6D7F}</SampleGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup />
+ <PropertyGroup>
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ <ImportToStore>False</ImportToStore>
+ <InstallMode>None</InstallMode>
+ <HardwareIdString />
+ <CommandLine />
+ <ScriptPath />
+ <DeployFiles />
+ <ScriptName />
+ <ScriptDeviceQuery>%PathToInf%</ScriptDeviceQuery>
+ <EnableVerifier>False</EnableVerifier>
+ <AllDrivers>False</AllDrivers>
+ <VerifyProjectOutput>True</VerifyProjectOutput>
+ <VerifyDrivers />
+ <VerifyFlags>133563</VerifyFlags>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
diff --git a/audio/simpleaudiosample/Package/package.VcxProj.Filters b/audio/simpleaudiosample/Package/package.VcxProj.Filters
new file mode 100644
index 00000000..63b75548
--- /dev/null
+++ b/audio/simpleaudiosample/Package/package.VcxProj.Filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{0924612D-FBA7-477E-BBB9-B3B6EA7C6B03}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{97311738-0AD8-4F7E-AC88-9C9BEAF53AEE}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{8DC1C4F0-C285-400E-A983-77A339891354}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{9F086F34-79D2-4FAA-87FD-C2DBEFCED0BA}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/audio/simpleaudiosample/README.md b/audio/simpleaudiosample/README.md
new file mode 100644
index 00000000..5309626a
--- /dev/null
+++ b/audio/simpleaudiosample/README.md
@@ -0,0 +1,133 @@
+---
+page_type: sample
+description: "The Microsoft Simple Audio Sample Device Driver shows how to develop a simple WDM audio driver that exposes support for two basic audio devices (a speaker and microphone array).”
+languages:
+- cpp
+products:
+- windows
+- windows-wdk
+---
+
+# Simple Audio Sample Device Driver
+
+## Introduction
+
+The Microsoft Simple Audio Sample Device Driver shows how to develop a simple WDM audio driver that exposes support for two basic audio devices (a speaker and microphone array). These audio devices are embedded in the system (not pluggable) and the driver uses WaveRT for rendering these devices. The driver also uses a "virtual audio device" instead of an actual hardware-based adapter.
+
+Driver developers can use the framework in this sample to provide support for various audio devices without concern for hardware dependencies. The framework includes implementations of the following interfaces:
+
+- The CAdapterCommon interface gives the miniports access to virtual mixer hardware. It also implements the **IAdapterPowerManagement** interface.
+
+- The CMiniportTopologySimpleAudioSample interface is the base class for all sample topologies. It has very basic common functions. In addition, this class contains common topology property handlers.
+
+The following table shows the contents of the various subdirectories of this sample.
+
+| Directory | Description |
+| --- | --- |
+| Source | Contains all of the source code for the Simple Audio Sample driver. |
+| Filters | Contains the definitions of the wave and topology filters of the endpoints that are present in the Simple Audio Sample driver (speaker and microphone array). |
+| Main | Contains the core functionality of the driver. |
+| Utilities | Contains helper files that provide additional functionality, such as a test tone generator and an audio file reader. |
+
+## Build the sample
+
+If you simply want to build this sample driver and don't intend to run or test it, then you do not need a target computer (also called a test computer). If, however, you would like to deploy, run and test this sample driver, then you need a second computer that will serve as your target computer. Instructions are provided in the **Run the sample** section to show you how to set up the target computer - also referred to as *provisioning* a target computer.
+
+Perform the following steps to build this sample driver.
+
+### 1. Open the driver solution in Visual Studio
+
+In Microsoft Visual Studio, Click **File** \> **Open** \> **Project/Solution...** and navigate to the folder that contains the sample files (for example, *C:\Windows-driver-samples\audio\SimpleAudioSample*). Double-click the *SimpleAudioSample* solution file.
+
+In Visual Studio locate the Solution Explorer. (If this is not already open, choose **Solution Explorer** from the **View** menu.) In Solution Explorer, you can see one solution that has five projects.
+
+### 2. Set the sample's configuration and platform
+
+In Solution Explorer, right-click **Solution ‘SimpleAudioSample’ (5 of 5 projects)**, and choose **Configuration Manager**. Make sure that the configuration and platform settings are the same for the five projects. By default, the configuration is set to **Debug**, and the platform is set to **Win32** for all the projects. If you make any configuration and/or platform changes for one project, you must make the same changes for all the remaining projects.
+
+### 3. Build the sample using Visual Studio
+
+In Visual Studio, click **Build** \> **Build Solution**.
+
+### 4. Locate the built driver package
+
+In File Explorer, navigate to the folder that contains the sample files. For example, you would navigate to *C:\\Windows-driver-samples\\audio\\SimpleAudioSample*, if that's the folder you specified in the preceding Step 1.
+
+In the folder, the location of the driver package varies depending on the configuration and platform settings that you selected in the **Configuration Manager**. For example, if you left the default settings unchanged, then the built driver package will be saved to a folder named *Debug* inside the same folder as the sample files. Double-click the folder for the built driver package, and then double-click the folder named *package*.
+
+The package should contain these files:
+
+| File | Description |
+| --- | --- |
+| SimpleAudioSample.sys | The driver file. |
+| SimpleAudioSample.cat | A signed catalog file, which serves as the signature for the entire package. |
+| SimpleAudioSample.inf | A non-componentized information (INF) file that contains information needed to install the driver. |
+
+## Run the sample
+
+The computer where you install the driver is called the *target computer* or the *test computer*. Typically this is a separate computer from the computer on which you develop and build the driver package. The computer where you develop and build the driver is called the *host computer*.
+
+The process of moving the driver package to the target computer and installing the driver is called *deploying* the driver. You can deploy the SimpleAudioSample driver automatically or manually.
+
+### Prepare the target computer
+
+First of all, install the latest [Windows Driver Kit](https://docs.microsoft.com/windows-hardware/drivers/download-the-wdk) (WDK) on the target computer.
+
+Before you manually deploy a driver, you must prepare the target computer by turning on test signing and by installing a certificate. You also need to locate the DevCon tool in your WDK installation. After that you're ready to run the built driver sample.
+
+Open a Command Prompt window as Administrator. Then enter the following command:
+
+`bcdedit /set TESTSIGNING ON`
+
+and reboot the target computer.
+
+> [!IMPORTANT]
+> Before using BCDEdit to change boot information you may need to temporarily suspend Windows security features such as BitLocker and Secure Boot on the test PC.
+
+Re-enable these security features when testing is complete and appropriately manage the test PC, when the security features are disabled.
+
+After rebooting, navigate to the Tools folder in your WDK installation and locate the DevCon tool. For example, look in the following folder:
+
+C:\\Program Files (x86)\\Windows Kits\\10\\Tools\\x64\\devcon.exe
+
+Copy *devcon.exe* to a folder on the target computer where it is easier to find. For example, create a *C:\\Tools* folder and copy *devcon.exe* to that folder.
+
+Create a folder on the target for the built driver package (for example, *C:\\SimpleAudioSampleDriver*). Copy all the files from the built driver package on the host computer and save them to the folder that you created on the target computer.
+
+Create a folder on the target computer for the certificate created by the build process. For example, you could create a folder named *C:\\Certificates* on the target computer, and then copy *package.cer* to it from the host computer. You can find this certificate in the same folder on the host computer, as the *package* folder that contains the built driver files. On the target computer, right-click the certificate file, and click **Install**, then follow the prompts to install the test certificate.
+
+If you need more detailed instructions for setting up the target computer, see [Preparing a Computer for Manual Driver Deployment](https://docs.microsoft.com/windows-hardware/drivers/develop/preparing-a-computer-for-manual-driver-deployment).
+
+#### A note on signatures
+
+Since most of these binary files are executed in kernel mode, it is important that they are signed and, optionally, to have a kernel debugger attached.
+
+Without any signature or kernel debugger, the driver will not be installed in the target computer. With a kernel debugger attached, the driver can be installed and the driver files (.sys extension) would be loaded. The only way of installing and executing the driver sample without a kernel debugger attached is to have both the .sys and .cat files signed with a trusted certificate.
+
+For more information on the subject, see [Driver signing](https://docs.microsoft.com/windows-hardware/drivers/install/driver-signing).
+
+### Install the driver
+
+To install SimpleAudioSample.inf, open a Command Prompt window as administrator on the target computer, then navigate to your driver package folder and enter the following command:
+
+`devcon install SimpleAudioSample.inf Root\SimpleAudioSample`
+
+If you get an error message about *devcon* not being recognized, try adding the path to the *devcon* tool. For example, if you copied it to a folder called *C:\\Tools*, then try using the following command:
+
+`C:\\tools\\devcon install SimpleAudioSample.inf Root\SimpleAudioSample`
+
+This installs the Simple Audio Sample driver with a hardware ID of "Root\SimpleAudioSample".
+
+Once the INF file is installed, a device should appear in Device Manager named *Microsoft Virtual Audio Device (WDM) - Simple Audio Sample*.
+
+After successfully installing the sample driver, you're now ready to test it.
+
+For more detailed instructions, see [Provision a computer for driver deployment and testing](https://docs.microsoft.com/windows-hardware/drivers/gettingstarted/provision-a-target-computer-wdk-8-1).
+
+### Test the driver
+
+On the target computer, in a Command Prompt window, enter **devmgmt.msc** to open Device Manager. In Device Manager, on the **View** menu, choose **Devices by type**. In the device tree, locate *Virtual Audio Device (WDM) – Simple Audio Sample*. This is typically under the **Sound, video and game controllers** node.
+
+On the target computer, open Control Panel and navigate to **Hardware and Sound** \> **Manage audio devices**. In the Sound dialog box, select the speaker icon labeled as *Virtual Audio Device (WDM) – Simple Audio Sample*, then click **Set Default**, but do not click **OK**. This will keep the Sound dialog box open.
+
+Locate an MP3 or other audio file on the target computer and double-click to play it. Then in the Sound dialog box, verify that there is activity in the volume level indicator associated with the *Virtual Audio Device (WDM) – Simple Audio Sample* driver.
diff --git a/audio/simpleaudiosample/SimpleAudioSample.sln b/audio/simpleaudiosample/SimpleAudioSample.sln
new file mode 100644
index 00000000..407838ba
--- /dev/null
+++ b/audio/simpleaudiosample/SimpleAudioSample.sln
@@ -0,0 +1,113 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30503.244
+MinimumVisualStudioVersion = 12.0
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Package", "Package", "{FA56D96B-290B-4C73-A5E1-02C1861D3224}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Filters", "Filters", "{952A7CB1-E516-44AA-AC38-4AEED9874C41}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utilities", "Utilities", "{0B4B8E51-20A8-43A4-A8DA-42FF90D628AC}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Inc", "Inc", "{C65091AE-E5B7-4359-8984-55852792406E}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Main", "Main", "{C06F6070-75EE-4F57-8D35-4AC2AB08D029}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "Package\package.VcxProj", "{830B14D5-0E32-4F9E-AEFA-4C9F6FC13C2A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Filters", "Source\Filters\Filters.vcxproj", "{771312CF-E5A2-4676-8142-86CEBDF99E2B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Utilities", "Source\Utilities\Utilities.vcxproj", "{33E61864-6F2C-4F9F-BE70-8F8985A4F283}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Inc", "Source\Inc\Inc.vcxproj", "{4B664BA5-057A-41B8-B365-2C99065C4DFA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Main", "Source\Main\Main.vcxproj", "{E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}"
+ ProjectSection(ProjectDependencies) = postProject
+ {33E61864-6F2C-4F9F-BE70-8F8985A4F283} = {33E61864-6F2C-4F9F-BE70-8F8985A4F283}
+ {771312CF-E5A2-4676-8142-86CEBDF99E2B} = {771312CF-E5A2-4676-8142-86CEBDF99E2B}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM64 = Debug|ARM64
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|ARM64 = Release|ARM64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {830B14D5-0E32-4F9E-AEFA-4C9F6FC13C2A}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {830B14D5-0E32-4F9E-AEFA-4C9F6FC13C2A}.Debug|ARM64.Build.0 = Debug|ARM64
+ {830B14D5-0E32-4F9E-AEFA-4C9F6FC13C2A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {830B14D5-0E32-4F9E-AEFA-4C9F6FC13C2A}.Debug|Win32.Build.0 = Debug|Win32
+ {830B14D5-0E32-4F9E-AEFA-4C9F6FC13C2A}.Debug|x64.ActiveCfg = Debug|x64
+ {830B14D5-0E32-4F9E-AEFA-4C9F6FC13C2A}.Debug|x64.Build.0 = Debug|x64
+ {830B14D5-0E32-4F9E-AEFA-4C9F6FC13C2A}.Release|ARM64.ActiveCfg = Release|ARM64
+ {830B14D5-0E32-4F9E-AEFA-4C9F6FC13C2A}.Release|ARM64.Build.0 = Release|ARM64
+ {830B14D5-0E32-4F9E-AEFA-4C9F6FC13C2A}.Release|Win32.ActiveCfg = Release|Win32
+ {830B14D5-0E32-4F9E-AEFA-4C9F6FC13C2A}.Release|Win32.Build.0 = Release|Win32
+ {830B14D5-0E32-4F9E-AEFA-4C9F6FC13C2A}.Release|x64.ActiveCfg = Release|x64
+ {830B14D5-0E32-4F9E-AEFA-4C9F6FC13C2A}.Release|x64.Build.0 = Release|x64
+ {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Debug|ARM64.Build.0 = Debug|ARM64
+ {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Debug|Win32.Build.0 = Debug|Win32
+ {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Debug|x64.ActiveCfg = Debug|x64
+ {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Debug|x64.Build.0 = Debug|x64
+ {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Release|ARM64.ActiveCfg = Release|ARM64
+ {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Release|ARM64.Build.0 = Release|ARM64
+ {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Release|Win32.ActiveCfg = Release|Win32
+ {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Release|Win32.Build.0 = Release|Win32
+ {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Release|x64.ActiveCfg = Release|x64
+ {771312CF-E5A2-4676-8142-86CEBDF99E2B}.Release|x64.Build.0 = Release|x64
+ {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Debug|ARM64.Build.0 = Debug|ARM64
+ {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Debug|Win32.ActiveCfg = Debug|Win32
+ {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Debug|Win32.Build.0 = Debug|Win32
+ {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Debug|x64.ActiveCfg = Debug|x64
+ {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Debug|x64.Build.0 = Debug|x64
+ {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Release|ARM64.ActiveCfg = Release|ARM64
+ {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Release|ARM64.Build.0 = Release|ARM64
+ {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Release|Win32.ActiveCfg = Release|Win32
+ {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Release|Win32.Build.0 = Release|Win32
+ {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Release|x64.ActiveCfg = Release|x64
+ {33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Release|x64.Build.0 = Release|x64
+ {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Debug|ARM64.Build.0 = Debug|ARM64
+ {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Debug|Win32.Build.0 = Debug|Win32
+ {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Debug|x64.ActiveCfg = Debug|x64
+ {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Debug|x64.Build.0 = Debug|x64
+ {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Release|ARM64.ActiveCfg = Release|ARM64
+ {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Release|ARM64.Build.0 = Release|ARM64
+ {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Release|Win32.ActiveCfg = Release|Win32
+ {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Release|Win32.Build.0 = Release|Win32
+ {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Release|x64.ActiveCfg = Release|x64
+ {4B664BA5-057A-41B8-B365-2C99065C4DFA}.Release|x64.Build.0 = Release|x64
+ {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Debug|ARM64.Build.0 = Debug|ARM64
+ {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Debug|Win32.Build.0 = Debug|Win32
+ {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Debug|x64.ActiveCfg = Debug|x64
+ {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Debug|x64.Build.0 = Debug|x64
+ {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Release|ARM64.ActiveCfg = Release|ARM64
+ {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Release|ARM64.Build.0 = Release|ARM64
+ {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Release|Win32.ActiveCfg = Release|Win32
+ {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Release|Win32.Build.0 = Release|Win32
+ {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Release|x64.ActiveCfg = Release|x64
+ {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {830B14D5-0E32-4F9E-AEFA-4C9F6FC13C2A} = {FA56D96B-290B-4C73-A5E1-02C1861D3224}
+ {771312CF-E5A2-4676-8142-86CEBDF99E2B} = {952A7CB1-E516-44AA-AC38-4AEED9874C41}
+ {33E61864-6F2C-4F9F-BE70-8F8985A4F283} = {0B4B8E51-20A8-43A4-A8DA-42FF90D628AC}
+ {4B664BA5-057A-41B8-B365-2C99065C4DFA} = {C65091AE-E5B7-4359-8984-55852792406E}
+ {E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF} = {C06F6070-75EE-4F57-8D35-4AC2AB08D029}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {6DB4FE19-4FE0-4DC4-B898-C46E01E6BDF4}
+ EndGlobalSection
+EndGlobal
diff --git a/audio/simpleaudiosample/Source/Filters/Filters.vcxproj b/audio/simpleaudiosample/Source/Filters/Filters.vcxproj
new file mode 100644
index 00000000..82fd07dc
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Filters/Filters.vcxproj
@@ -0,0 +1,282 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|ARM64">
+ <Configuration>Debug</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|ARM64">
+ <Configuration>Release</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{771312CF-E5A2-4676-8142-86CEBDF99E2B}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{F51739CE-5253-42B5-9191-57F28B5842C6}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>Filters</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <TargetName>Filters</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>Filters</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <TargetName>Filters</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>Filters</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>Filters</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="micarraytopo.cpp" />
+ <ClCompile Include="speakertopo.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>
diff --git a/audio/simpleaudiosample/Source/Filters/Filters.vcxproj.Filters b/audio/simpleaudiosample/Source/Filters/Filters.vcxproj.Filters
new file mode 100644
index 00000000..b573243b
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Filters/Filters.vcxproj.Filters
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{75C3E63D-04EA-4EB3-B9F1-505497C51F71}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{5E8F8D4C-2886-4109-9E78-CE5EA6DB4AC4}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{75D3016A-4ED8-4FAF-9817-394BE1112534}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="*.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project>
diff --git a/audio/simpleaudiosample/Source/Filters/micarray1toptable.h b/audio/simpleaudiosample/Source/Filters/micarray1toptable.h
new file mode 100644
index 00000000..3bbd80f3
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Filters/micarray1toptable.h
@@ -0,0 +1,210 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ micarray1toptable.h
+
+Abstract:
+
+ Declaration of topology tables for the mic array.
+
+--*/
+
+#ifndef _SIMPLEAUDIOSAMPLE_MICARRAY1TOPTABLE_H_
+#define _SIMPLEAUDIOSAMPLE_MICARRAY1TOPTABLE_H_
+
+//
+// {6ae81ff4-203e-4fe1-88aa-f2d57775cd4a}
+DEFINE_GUID(MICARRAY1_CUSTOM_NAME,
+ 0x6ae81ff4, 0x203e, 0x4fe1, 0x88, 0xaa, 0xf2, 0xd5, 0x77, 0x75, 0xcd, 0x4a);
+
+//=============================================================================
+static
+KSDATARANGE MicArray1TopoPinDataRangesBridge[] =
+{
+ {
+ sizeof(KSDATARANGE),
+ 0,
+ 0,
+ 0,
+ STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
+ STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
+ }
+};
+
+//=============================================================================
+static
+PKSDATARANGE MicArray1TopoPinDataRangePointersBridge[] =
+{
+ &MicArray1TopoPinDataRangesBridge[0]
+};
+
+//=============================================================================
+static
+PCPIN_DESCRIPTOR MicArray1TopoMiniportPins[] =
+{
+ // KSPIN_TOPO_MIC_ELEMENTS
+ {
+ 0,
+ 0,
+ 0, // InstanceCount
+ NULL, // AutomationTable
+ { // KsPinDescriptor
+ 0, // InterfacesCount
+ NULL, // Interfaces
+ 0, // MediumsCount
+ NULL, // Mediums
+ SIZEOF_ARRAY(MicArray1TopoPinDataRangePointersBridge), // DataRangesCount
+ MicArray1TopoPinDataRangePointersBridge, // DataRanges
+ KSPIN_DATAFLOW_IN, // DataFlow
+ KSPIN_COMMUNICATION_NONE, // Communication
+ &KSNODETYPE_MICROPHONE_ARRAY, // Category
+ &MICARRAY1_CUSTOM_NAME, // Name
+ 0 // Reserved
+ }
+ },
+
+ // KSPIN_TOPO_BRIDGE
+ {
+ 0,
+ 0,
+ 0, // InstanceCount
+ NULL, // AutomationTable
+ { // KsPinDescriptor
+ 0, // InterfacesCount
+ NULL, // Interfaces
+ 0, // MediumsCount
+ NULL, // Mediums
+ SIZEOF_ARRAY(MicArray1TopoPinDataRangePointersBridge), // DataRangesCount
+ MicArray1TopoPinDataRangePointersBridge, // DataRanges
+ KSPIN_DATAFLOW_OUT, // DataFlow
+ KSPIN_COMMUNICATION_NONE, // Communication
+ &KSCATEGORY_AUDIO, // Category
+ NULL, // Name
+ 0 // Reserved
+ }
+ }
+};
+
+//=============================================================================
+static
+PCPROPERTY_ITEM MicArray1PropertiesVolume[] =
+{
+ {
+ &KSPROPSETID_Audio,
+ KSPROPERTY_AUDIO_VOLUMELEVEL,
+ KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_MicArrayTopology
+ }
+};
+
+DEFINE_PCAUTOMATION_TABLE_PROP(AutomationMicArray1Volume, MicArray1PropertiesVolume);
+
+//=============================================================================
+static
+PCPROPERTY_ITEM MicArray1PropertiesMute[] =
+{
+ {
+ &KSPROPSETID_Audio,
+ KSPROPERTY_AUDIO_MUTE,
+ KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_MicArrayTopology
+ }
+};
+
+DEFINE_PCAUTOMATION_TABLE_PROP(AutomationMicArray1Mute, MicArray1PropertiesMute);
+
+//=============================================================================
+static
+PCNODE_DESCRIPTOR MicArray1TopologyNodes[] =
+{
+ // KSNODE_TOPO_VOLUME
+ {
+ 0, // Flags
+ &AutomationMicArray1Volume, // AutomationTable
+ &KSNODETYPE_VOLUME, // Type
+ &KSAUDFNAME_MIC_VOLUME // Name
+ },
+ // KSNODE_TOPO_MUTE
+ {
+ 0, // Flags
+ &AutomationMicArray1Mute, // AutomationTable
+ &KSNODETYPE_MUTE, // Type
+ &KSAUDFNAME_MIC_MUTE // Name
+ }
+};
+
+C_ASSERT(KSNODE_TOPO_VOLUME == 0);
+C_ASSERT(KSNODE_TOPO_MUTE == 1);
+
+static
+PCCONNECTION_DESCRIPTOR MicArray1TopoMiniportConnections[] =
+{
+ // FromNode, FromPin, ToNode, ToPin
+ { PCFILTER_NODE, KSPIN_TOPO_MIC_ELEMENTS, KSNODE_TOPO_VOLUME, 1 },
+ { KSNODE_TOPO_VOLUME, 0, KSNODE_TOPO_MUTE, 1 },
+ { KSNODE_TOPO_MUTE, 0, PCFILTER_NODE, KSPIN_TOPO_BRIDGE }
+};
+
+
+
+//=============================================================================
+static
+PCPROPERTY_ITEM MicArray1PropertiesTopoFilter[] =
+{
+ {
+ &KSPROPSETID_Jack,
+ KSPROPERTY_JACK_DESCRIPTION,
+ KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_MicArrayTopoFilter
+ },
+ {
+ &KSPROPSETID_Jack,
+ KSPROPERTY_JACK_DESCRIPTION2,
+ KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_MicArrayTopoFilter
+ },
+ {
+ &KSPROPSETID_Audio,
+ KSPROPERTY_AUDIO_MIC_ARRAY_GEOMETRY,
+ KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_MicArrayTopoFilter
+ },
+ {
+ &KSPROPSETID_Audio,
+ KSPROPERTY_AUDIO_MIC_SNR,
+ KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_MicArrayTopoFilter
+ },
+ {
+ &KSPROPSETID_Audio,
+ KSPROPERTY_AUDIO_MIC_SENSITIVITY2,
+ KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_MicArrayTopoFilter
+ }
+};
+
+DEFINE_PCAUTOMATION_TABLE_PROP(AutomationMicArray1TopoFilter, MicArray1PropertiesTopoFilter);
+
+//=============================================================================
+static
+PCFILTER_DESCRIPTOR MicArray1TopoMiniportFilterDescriptor =
+{
+ 0, // Version
+ &AutomationMicArray1TopoFilter, // AutomationTable
+ sizeof(PCPIN_DESCRIPTOR), // PinSize
+ SIZEOF_ARRAY(MicArray1TopoMiniportPins), // PinCount
+ MicArray1TopoMiniportPins, // Pins
+ sizeof(PCNODE_DESCRIPTOR), // NodeSize
+ SIZEOF_ARRAY(MicArray1TopologyNodes), // NodeCount
+ MicArray1TopologyNodes, // Nodes
+ SIZEOF_ARRAY(MicArray1TopoMiniportConnections),// ConnectionCount
+ MicArray1TopoMiniportConnections, // Connections
+ 0, // CategoryCount
+ NULL // Categories
+};
+
+#endif // _SIMPLEAUDIOSAMPLE_MICARRAY1TOPTABLE_H_
diff --git a/audio/simpleaudiosample/Source/Filters/micarraytopo.cpp b/audio/simpleaudiosample/Source/Filters/micarraytopo.cpp
new file mode 100644
index 00000000..66cc7d89
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Filters/micarraytopo.cpp
@@ -0,0 +1,825 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ micarraytopo.cpp
+
+Abstract:
+
+ Implementation of topology miniport for the mic array.
+
+--*/
+
+#pragma warning (disable : 4127)
+
+#include "definitions.h"
+#include "endpoints.h"
+#include "common.h"
+#include "kshelper.h"
+#include "micarraytopo.h"
+#include "micarray1toptable.h"
+
+constexpr float MICARRAY_SENSITIVITY = -46.5f;
+constexpr float MICARRAY_SENSITIVITY2 = -23.5f;
+constexpr float MICARRAY_SNR = 66.0f;
+
+constexpr inline LONG FloatToFixedPoint16_16(float fl)
+{
+ return (static_cast<LONG>((fl) * (65536.0f)));
+}
+
+#pragma code_seg("PAGE")
+
+//=============================================================================
+NTSTATUS
+CreateMicArrayMiniportTopology
+(
+ _Out_ PUNKNOWN* Unknown,
+ _In_ REFCLSID,
+ _In_opt_ PUNKNOWN UnknownOuter,
+ _In_ POOL_FLAGS PoolFlags,
+ _In_ PUNKNOWN UnknownAdapter,
+ _In_opt_ PVOID DeviceContext,
+ _In_ PENDPOINT_MINIPAIR MiniportPair
+)
+/*++
+
+Routine Description:
+
+ Creates a new topology miniport.
+
+Arguments:
+
+ Unknown -
+
+ RefclsId -
+
+ UnknownOuter -
+
+ PoolType -
+
+ UnknownAdapter -
+
+ DeviceContext -
+
+ MiniportPair -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(Unknown);
+ ASSERT(MiniportPair);
+
+ UNREFERENCED_PARAMETER(UnknownAdapter);
+ UNREFERENCED_PARAMETER(DeviceContext);
+
+ CMicArrayMiniportTopology* obj =
+ new (PoolFlags, MINTOPORT_POOLTAG)
+ CMicArrayMiniportTopology(UnknownOuter,
+ MiniportPair->TopoDescriptor,
+ MiniportPair->DeviceMaxChannels,
+ MiniportPair->DeviceType);
+ if (NULL == obj)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ obj->AddRef();
+
+ *Unknown = reinterpret_cast<IUnknown*>(obj);
+
+ return STATUS_SUCCESS;
+} // CreateMicArrayMiniportTopology
+
+//=============================================================================
+CMicArrayMiniportTopology::~CMicArrayMiniportTopology
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Topology miniport destructor
+
+Arguments:
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMicArrayMiniportTopology::~CMicArrayMiniportTopology]"));
+} // ~CMicArrayMiniportTopology
+
+//=============================================================================
+NTSTATUS
+CMicArrayMiniportTopology::DataRangeIntersection
+(
+ _In_ ULONG PinId,
+ _In_ PKSDATARANGE ClientDataRange,
+ _In_ PKSDATARANGE MyDataRange,
+ _In_ ULONG OutputBufferLength,
+ _Out_writes_bytes_to_opt_(OutputBufferLength, *ResultantFormatLength)
+ PVOID ResultantFormat OPTIONAL,
+ _Out_ PULONG ResultantFormatLength
+)
+/*++
+
+Routine Description:
+
+ The DataRangeIntersection function determines the highest quality
+ intersection of two data ranges.
+
+Arguments:
+
+ PinId - Pin for which data intersection is being determined.
+
+ ClientDataRange - Pointer to KSDATARANGE structure which contains the data range
+ submitted by client in the data range intersection property
+ request.
+
+ MyDataRange - Pin's data range to be compared with client's data range.
+
+ OutputBufferLength - Size of the buffer pointed to by the resultant format
+ parameter.
+
+ ResultantFormat - Pointer to value where the resultant format should be
+ returned.
+
+ ResultantFormatLength - Actual length of the resultant format that is placed
+ at ResultantFormat. This should be less than or equal
+ to OutputBufferLength.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ return
+ CMiniportTopologySimpleAudioSample::DataRangeIntersection
+ (
+ PinId,
+ ClientDataRange,
+ MyDataRange,
+ OutputBufferLength,
+ ResultantFormat,
+ ResultantFormatLength
+ );
+} // DataRangeIntersection
+
+//=============================================================================
+STDMETHODIMP
+CMicArrayMiniportTopology::GetDescription
+(
+ _Out_ PPCFILTER_DESCRIPTOR* OutFilterDescriptor
+)
+/*++
+
+Routine Description:
+
+ The GetDescription function gets a pointer to a filter description.
+ It provides a location to deposit a pointer in miniport's description
+ structure. This is the placeholder for the FromNode or ToNode fields in
+ connections which describe connections to the filter's pins.
+
+Arguments:
+
+ OutFilterDescriptor - Pointer to the filter description.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(OutFilterDescriptor);
+
+ return CMiniportTopologySimpleAudioSample::GetDescription(OutFilterDescriptor);
+} // GetDescription
+
+//=============================================================================
+STDMETHODIMP
+CMicArrayMiniportTopology::Init
+(
+ _In_ PUNKNOWN UnknownAdapter,
+ _In_ PRESOURCELIST ResourceList,
+ _In_ PPORTTOPOLOGY Port_
+)
+/*++
+
+Routine Description:
+
+ The Init function initializes the miniport. Callers of this function
+ should run at IRQL PASSIVE_LEVEL
+
+Arguments:
+
+ UnknownAdapter - A pointer to the IUnknown interface of the adapter object.
+
+ ResourceList - Pointer to the resource list to be supplied to the miniport
+ during initialization. The port driver is free to examine the
+ contents of the ResourceList. The port driver will not be
+ modify the ResourceList contents.
+
+ Port - Pointer to the topology port object that is linked with this miniport.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(ResourceList);
+
+ PAGED_CODE();
+
+ ASSERT(UnknownAdapter);
+ ASSERT(Port_);
+
+ DPF_ENTER(("[CMicArrayMiniportTopology::Init]"));
+
+ NTSTATUS ntStatus;
+
+ ntStatus =
+ CMiniportTopologySimpleAudioSample::Init
+ (
+ UnknownAdapter,
+ Port_
+ );
+
+ return ntStatus;
+} // Init
+
+//=============================================================================
+STDMETHODIMP
+CMicArrayMiniportTopology::NonDelegatingQueryInterface
+(
+ _In_ REFIID Interface,
+ _COM_Outptr_ PVOID* Object
+)
+/*++
+
+Routine Description:
+
+ QueryInterface for MiniportTopology
+
+Arguments:
+
+ Interface - GUID of the interface
+
+ Object - interface object to be returned.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(Object);
+
+ if (IsEqualGUIDAligned(Interface, IID_IUnknown))
+ {
+ *Object = PVOID(PUNKNOWN(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniport))
+ {
+ *Object = PVOID(PMINIPORT(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniportTopology))
+ {
+ *Object = PVOID(PMINIPORTTOPOLOGY(this));
+ }
+ else
+ {
+ *Object = NULL;
+ }
+
+ if (*Object)
+ {
+ // We reference the interface for the caller.
+ PUNKNOWN(*Object)->AddRef();
+ return(STATUS_SUCCESS);
+ }
+
+ return(STATUS_INVALID_PARAMETER);
+} // NonDelegatingQueryInterface
+
+//=============================================================================
+NTSTATUS
+CMicArrayMiniportTopology::PropertyHandlerMicArrayGeometry
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Handles ( KSPROPSETID_Audio, KSPROPERTY_AUDIO_MIC_ARRAY_GEOMETRY )
+
+Arguments:
+
+ PropertyRequest -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(PropertyRequest);
+
+ DPF_ENTER(("[PropertyHandlerMicArrayGeometry]"));
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ ULONG nPinId = (ULONG)-1;
+
+ if (PropertyRequest->InstanceSize >= sizeof(ULONG))
+ {
+ nPinId = *(PULONG(PropertyRequest->Instance));
+
+ if (nPinId == KSPIN_TOPO_MIC_ELEMENTS)
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ntStatus =
+ PropertyHandler_BasicSupport
+ (
+ PropertyRequest,
+ KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
+ VT_ILLEGAL
+ );
+ }
+ else
+ {
+ ULONG cElements = 2;
+ ULONG cbNeeded = FIELD_OFFSET(KSAUDIO_MIC_ARRAY_GEOMETRY, KsMicCoord) +
+ cElements * sizeof(KSAUDIO_MICROPHONE_COORDINATES);
+
+ if (PropertyRequest->ValueSize == 0)
+ {
+ PropertyRequest->ValueSize = cbNeeded;
+ ntStatus = STATUS_BUFFER_OVERFLOW;
+ }
+ else if (PropertyRequest->ValueSize < cbNeeded)
+ {
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ PKSAUDIO_MIC_ARRAY_GEOMETRY pMAG = (PKSAUDIO_MIC_ARRAY_GEOMETRY)PropertyRequest->Value;
+ const SHORT MicArray_180_Degrees = 31416; // 10000 * pi
+ const SHORT MicArray_45_Degrees = 7854; // 10000 * pi / 4
+
+ // fill in mic array geometry fields
+ pMAG->usVersion = 0x0100; // Version of Mic array specification (0x0100)
+ pMAG->usMicArrayType = (USHORT)KSMICARRAY_MICARRAYTYPE_LINEAR; // Type of Mic Array
+ pMAG->wVerticalAngleBegin = -MicArray_45_Degrees; // Work Volume Vertical Angle Begin
+ pMAG->wVerticalAngleEnd = MicArray_45_Degrees; // Work Volume Vertical Angle End
+ pMAG->wHorizontalAngleBegin = 0; // Work Volume HorizontalAngle Begin
+ pMAG->wHorizontalAngleEnd = 0; // Work Volume HorizontalAngle End
+ pMAG->usFrequencyBandLo = 100; // Low end of Freq Range
+ pMAG->usFrequencyBandHi = 8000; // High end of Freq Range
+
+ pMAG->usNumberOfMicrophones = 2; // Count of microphone coordinate structures to follow.
+
+ pMAG->KsMicCoord[0].usType = (USHORT)KSMICARRAY_MICTYPE_CARDIOID;
+ pMAG->KsMicCoord[0].wXCoord = 0;
+ pMAG->KsMicCoord[0].wYCoord = 100;
+ pMAG->KsMicCoord[0].wZCoord = 0;
+ pMAG->KsMicCoord[0].wVerticalAngle = 0;
+ pMAG->KsMicCoord[0].wHorizontalAngle = 0;
+
+ pMAG->KsMicCoord[1].usType = (USHORT)KSMICARRAY_MICTYPE_CARDIOID;
+ pMAG->KsMicCoord[1].wXCoord = 0;
+ pMAG->KsMicCoord[1].wYCoord = -100;
+ pMAG->KsMicCoord[1].wZCoord = 0;
+ pMAG->KsMicCoord[1].wVerticalAngle = 0;
+ pMAG->KsMicCoord[1].wHorizontalAngle = 0;
+ ntStatus = STATUS_SUCCESS;
+ }
+ }
+ }
+ }
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+NTSTATUS
+CMicArrayMiniportTopology::PropertyHandlerMicProperties
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+Handles ( KSPROPSETID_Audio, KSPROPERTY_AUDIO_MIC_SNR )
+Handles ( KSPROPSETID_Audio, KSPROPERTY_AUDIO_MIC_SENSITIVITY2 )
+
+Arguments:
+
+PropertyRequest -
+
+Return Value:
+
+NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(PropertyRequest);
+
+ DPF_ENTER(("[PropertyHandlerMicProperties]"));
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ ULONG nPinId = (ULONG)-1;
+ KFLOATING_SAVE saveData;
+ NTSTATUS fstatus;
+
+ if (PropertyRequest->InstanceSize >= sizeof(ULONG))
+ {
+ nPinId = *(PULONG(PropertyRequest->Instance));
+
+ if (nPinId == KSPIN_TOPO_MIC_ELEMENTS)
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ntStatus =
+ PropertyHandler_BasicSupport
+ (
+ PropertyRequest,
+ KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
+ VT_ILLEGAL
+ );
+ }
+ else
+ {
+ ntStatus =
+ ValidatePropertyParams
+ (
+ PropertyRequest,
+ sizeof(LONG),
+ 0
+ );
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ if (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_MIC_SNR)
+ {
+ LONG* micSNR = (LONG*)PropertyRequest->Value;
+ fstatus = KeSaveFloatingPointState(&saveData);
+ if (NT_SUCCESS(fstatus))
+ {
+ // Return microphone SNR information.
+ *micSNR = FloatToFixedPoint16_16(MICARRAY_SNR); // convert float dB to fixed point arithmetic
+ KeRestoreFloatingPointState(&saveData);
+ }
+ ntStatus = STATUS_SUCCESS;
+ }
+ else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_MIC_SENSITIVITY2)
+ {
+ LONG* micSensitivity2 = (LONG*)PropertyRequest->Value;
+ fstatus = KeSaveFloatingPointState(&saveData);
+ if (NT_SUCCESS(fstatus))
+ {
+ // Return microphone SNR information.
+ *micSensitivity2 = FloatToFixedPoint16_16(MICARRAY_SENSITIVITY2); // convert float dB to fixed point arithmetic
+ KeRestoreFloatingPointState(&saveData);
+ }
+ ntStatus = STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ }
+ }
+ }
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+NTSTATUS
+CMicArrayMiniportTopology::PropertyHandlerJackDescription
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION )
+
+Arguments:
+
+ PropertyRequest -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(PropertyRequest);
+
+ DPF_ENTER(("[PropertyHandlerJackDescription]"));
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ ULONG nPinId = (ULONG)-1;
+
+ if (PropertyRequest->InstanceSize >= sizeof(ULONG))
+ {
+ nPinId = *(PULONG(PropertyRequest->Instance));
+
+ if (nPinId == KSPIN_TOPO_MIC_ELEMENTS)
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ntStatus =
+ PropertyHandler_BasicSupport
+ (
+ PropertyRequest,
+ KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
+ VT_ILLEGAL
+ );
+ }
+ else
+ {
+ ULONG cbNeeded = sizeof(KSMULTIPLE_ITEM) + sizeof(KSJACK_DESCRIPTION);
+
+ if (PropertyRequest->ValueSize == 0)
+ {
+ PropertyRequest->ValueSize = cbNeeded;
+ ntStatus = STATUS_BUFFER_OVERFLOW;
+ }
+ else if (PropertyRequest->ValueSize < cbNeeded)
+ {
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ PKSMULTIPLE_ITEM pMI = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
+ PKSJACK_DESCRIPTION pDesc = (PKSJACK_DESCRIPTION)(pMI + 1);
+
+ pMI->Size = cbNeeded;
+ pMI->Count = 1;
+
+ pDesc->ChannelMapping = 0; // Don't specify channel mask for array mic
+ pDesc->Color = 0x00000000; // Black. This is an integrated device
+ pDesc->ConnectionType = eConnTypeUnknown; // Integrated.
+ pDesc->GenLocation = eGenLocPrimaryBox;
+ pDesc->GeoLocation = eGeoLocFront;
+ pDesc->PortConnection = ePortConnIntegratedDevice;
+ pDesc->IsConnected = TRUE; // This is an integrated device, so it's always "connected"
+
+ ntStatus = STATUS_SUCCESS;
+ }
+ }
+ }
+ }
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+NTSTATUS
+CMicArrayMiniportTopology::PropertyHandlerJackDescription2
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION2 )
+
+Arguments:
+
+ PropertyRequest -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(PropertyRequest);
+
+ DPF_ENTER(("[PropertyHandlerJackDescription2]"));
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ ULONG nPinId = (ULONG)-1;
+
+ if (PropertyRequest->InstanceSize >= sizeof(ULONG))
+ {
+ nPinId = *(PULONG(PropertyRequest->Instance));
+
+ if (nPinId == KSPIN_TOPO_MIC_ELEMENTS)
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ntStatus =
+ PropertyHandler_BasicSupport
+ (
+ PropertyRequest,
+ KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
+ VT_ILLEGAL
+ );
+ }
+ else
+ {
+ ULONG cbNeeded = sizeof(KSMULTIPLE_ITEM) + sizeof(KSJACK_DESCRIPTION2);
+
+ if (PropertyRequest->ValueSize == 0)
+ {
+ PropertyRequest->ValueSize = cbNeeded;
+ ntStatus = STATUS_BUFFER_OVERFLOW;
+ }
+ else if (PropertyRequest->ValueSize < cbNeeded)
+ {
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ PKSMULTIPLE_ITEM pMI = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
+ PKSJACK_DESCRIPTION2 pDesc = (PKSJACK_DESCRIPTION2)(pMI + 1);
+
+ pMI->Size = cbNeeded;
+ pMI->Count = 1;
+
+ RtlZeroMemory(pDesc, sizeof(KSJACK_DESCRIPTION2));
+
+ //
+ // Specifies the lower 16 bits of the DWORD parameter. This parameter indicates whether
+ // the jack is currently active, streaming, idle, or hardware not ready.
+ //
+ pDesc->DeviceStateInfo = 0;
+
+ //
+ // From MSDN:
+ // "If an audio device lacks jack presence detection, the IsConnected member of
+ // the KSJACK_DESCRIPTION structure must always be set to TRUE. To remove the
+ // ambiguity that results from this dual meaning of the TRUE value for IsConnected,
+ // a client application can call IKsJackDescription2::GetJackDescription2 to read
+ // the JackCapabilities flag of the KSJACK_DESCRIPTION2 structure. If this flag has
+ // the JACKDESC2_PRESENCE_DETECT_CAPABILITY bit set, it indicates that the endpoint
+ // does in fact support jack presence detection. In that case, the return value of
+ // the IsConnected member can be interpreted to accurately reflect the insertion status
+ // of the jack."
+ //
+ // Bit definitions:
+ // 0x00000001 - JACKDESC2_PRESENCE_DETECT_CAPABILITY
+ // 0x00000002 - JACKDESC2_DYNAMIC_FORMAT_CHANGE_CAPABILITY
+ //
+ pDesc->JackCapabilities = 0;
+
+ ntStatus = STATUS_SUCCESS;
+ }
+ }
+ }
+ }
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+NTSTATUS
+PropertyHandler_MicArrayTopoFilter
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Redirects property request to miniport object
+
+Arguments:
+
+ PropertyRequest -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(PropertyRequest);
+
+ DPF_ENTER(("[PropertyHandler_MicArrayTopoFilter]"));
+
+ // PropertryRequest structure is filled by portcls.
+ // MajorTarget is a pointer to miniport object for miniports.
+ //
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ PCMicArrayMiniportTopology pMiniport = (PCMicArrayMiniportTopology)PropertyRequest->MajorTarget;
+
+ if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Audio))
+ {
+ if (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_MIC_ARRAY_GEOMETRY)
+ {
+ ntStatus = pMiniport->PropertyHandlerMicArrayGeometry(PropertyRequest);
+ }
+ else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_MIC_SENSITIVITY2)
+ {
+ ntStatus = pMiniport->PropertyHandlerMicProperties(PropertyRequest);
+ }
+ else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_MIC_SNR)
+ {
+ ntStatus = pMiniport->PropertyHandlerMicProperties(PropertyRequest);
+ }
+ }
+ else if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Jack))
+ {
+ if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION)
+ {
+ ntStatus = pMiniport->PropertyHandlerJackDescription(PropertyRequest);
+ }
+ else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION2)
+ {
+ ntStatus = pMiniport->PropertyHandlerJackDescription2(PropertyRequest);
+ }
+ }
+
+ return ntStatus;
+} // PropertyHandler_TopoFilter
+
+//=============================================================================
+NTSTATUS
+PropertyHandler_MicArrayTopology
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Redirects property request to miniport object
+
+Arguments:
+
+ PropertyRequest -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(PropertyRequest);
+
+ DPF_ENTER(("[PropertyHandler_MicArrayTopology]"));
+
+ // PropertryRequest structure is filled by portcls.
+ // MajorTarget is a pointer to miniport object for miniports.
+ //
+ PCMicArrayMiniportTopology pMiniport = (PCMicArrayMiniportTopology)PropertyRequest->MajorTarget;
+
+ return pMiniport->PropertyHandlerGeneric(PropertyRequest);
+} // PropertyHandler_MicArrayTopology
+
+#pragma code_seg()
diff --git a/audio/simpleaudiosample/Source/Filters/micarraytopo.h b/audio/simpleaudiosample/Source/Filters/micarraytopo.h
new file mode 100644
index 00000000..4f4a621f
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Filters/micarraytopo.h
@@ -0,0 +1,97 @@
+
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ micarraytopo.h
+
+Abstract:
+
+ Declaration of mic array topology miniport.
+
+--*/
+
+#ifndef _SIMPLEAUDIOSAMPLE_MICARRAYTOPO_H_
+#define _SIMPLEAUDIOSAMPLE_MICARRAYTOPO_H_
+
+#include "basetopo.h"
+
+//=============================================================================
+// Classes
+//=============================================================================
+
+///////////////////////////////////////////////////////////////////////////////
+// CMicArrayMiniportTopology
+//
+
+#pragma code_seg()
+class CMicArrayMiniportTopology :
+ public CMiniportTopologySimpleAudioSample,
+ public IMiniportTopology,
+ public CUnknown
+{
+public:
+ DECLARE_STD_UNKNOWN();
+ CMicArrayMiniportTopology
+ (
+ _In_opt_ PUNKNOWN UnknownOuter,
+ _In_ PCFILTER_DESCRIPTOR* FilterDesc,
+ _In_ USHORT DeviceMaxChannels,
+ _In_ eDeviceType DeviceType
+ )
+ : CUnknown(UnknownOuter),
+ CMiniportTopologySimpleAudioSample(FilterDesc, DeviceMaxChannels),
+ m_DeviceType(DeviceType)
+ {
+ ASSERT(m_DeviceType == eMicArrayDevice1);
+ }
+
+ ~CMicArrayMiniportTopology();
+
+ IMP_IMiniportTopology;
+
+ NTSTATUS PropertyHandlerMicArrayGeometry
+ (
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+ );
+
+ NTSTATUS PropertyHandlerMicProperties
+ (
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+ );
+
+ NTSTATUS PropertyHandlerJackDescription
+ (
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+ );
+
+ NTSTATUS PropertyHandlerJackDescription2
+ (
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+ );
+
+protected:
+ eDeviceType m_DeviceType;
+
+};
+
+typedef CMicArrayMiniportTopology* PCMicArrayMiniportTopology;
+
+
+NTSTATUS
+CreateMicArrayMiniportTopology(
+ _Out_ PUNKNOWN* Unknown,
+ _In_ REFCLSID,
+ _In_opt_ PUNKNOWN UnknownOuter,
+ _In_ POOL_FLAGS PoolFlags,
+ _In_ PUNKNOWN UnknownAdapter,
+ _In_opt_ PVOID DeviceContext,
+ _In_ PENDPOINT_MINIPAIR MiniportPair
+);
+
+NTSTATUS PropertyHandler_MicArrayTopoFilter(_In_ PPCPROPERTY_REQUEST PropertyRequest);
+NTSTATUS PropertyHandler_MicArrayTopology(_In_ PPCPROPERTY_REQUEST PropertyRequest);
+
+#endif // _SIMPLEAUDIOSAMPLE_MICARRAYTOPO_H_
diff --git a/audio/simpleaudiosample/Source/Filters/micarraywavtable.h b/audio/simpleaudiosample/Source/Filters/micarraywavtable.h
new file mode 100644
index 00000000..53656038
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Filters/micarraywavtable.h
@@ -0,0 +1,292 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ micarraywavtable.h
+
+Abstract:-
+
+ Declaration of wave miniport tables for the mic array.
+
+--*/
+
+#ifndef _SIMPLEAUDIOSAMPLE_MICARRAYWAVTABLE_H_
+#define _SIMPLEAUDIOSAMPLE_MICARRAYWAVTABLE_H_
+
+//
+// Mic array range.
+//
+#define MICARRAY_RAW_CHANNELS 2 // Channels for raw mode
+#define MICARRAY_DEVICE_MAX_CHANNELS 2 // Max channels overall
+#define MICARRAY_32_BITS_PER_SAMPLE_PCM 32 // 32 Bits Per Sample
+#define MICARRAY_RAW_SAMPLE_RATE 48000 // Raw sample rate
+
+//
+// Max # of pin instances.
+//
+#define MICARRAY_MAX_INPUT_STREAMS 1
+
+//=============================================================================
+static
+KSDATAFORMAT_WAVEFORMATEXTENSIBLE MicArrayPinSupportedDeviceFormats[] =
+{
+ // 48 KHz 32-bit 2 channels
+ {
+ {
+ sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
+ 0,
+ 0,
+ 0,
+ STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
+ STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
+ },
+ {
+ {
+ WAVE_FORMAT_EXTENSIBLE,
+ 2,
+ 48000,
+ 384000,
+ 8,
+ 32,
+ sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
+ },
+ 32,
+ KSAUDIO_SPEAKER_STEREO,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
+ }
+ }
+};
+
+//
+// Supported modes (only on streaming pins).
+//
+static
+MODE_AND_DEFAULT_FORMAT MicArrayPinSupportedDeviceModes[] =
+{
+ {
+ STATIC_AUDIO_SIGNALPROCESSINGMODE_RAW,
+ &MicArrayPinSupportedDeviceFormats[0].DataFormat
+ }
+};
+
+//
+// The entries here must follow the same order as the filter's pin
+// descriptor array.
+//
+static
+PIN_DEVICE_FORMATS_AND_MODES MicArrayPinDeviceFormatsAndModes[] =
+{
+ {
+ BridgePin,
+ NULL,
+ 0,
+ NULL,
+ 0
+ },
+ {
+ SystemCapturePin,
+ MicArrayPinSupportedDeviceFormats,
+ SIZEOF_ARRAY(MicArrayPinSupportedDeviceFormats),
+ MicArrayPinSupportedDeviceModes,
+ SIZEOF_ARRAY(MicArrayPinSupportedDeviceModes)
+ }
+};
+
+//=============================================================================
+// Data ranges
+//
+// See CMiniportWaveRT::DataRangeIntersection.
+//
+static
+KSDATARANGE_AUDIO MicArrayPinDataRangesRawStream[] =
+{
+ {
+ {
+ sizeof(KSDATARANGE_AUDIO),
+ KSDATARANGE_ATTRIBUTES, // An attributes list follows this data range
+ 0,
+ 0,
+ STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
+ STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
+ },
+ MICARRAY_RAW_CHANNELS,
+ MICARRAY_32_BITS_PER_SAMPLE_PCM,
+ MICARRAY_32_BITS_PER_SAMPLE_PCM,
+ MICARRAY_RAW_SAMPLE_RATE,
+ MICARRAY_RAW_SAMPLE_RATE
+ },
+};
+
+static
+PKSDATARANGE MicArrayPinDataRangePointersStream[] =
+{
+ // All supported device formats should be listed in the DataRange.
+ PKSDATARANGE(&MicArrayPinDataRangesRawStream[0]),
+ PKSDATARANGE(&PinDataRangeAttributeList),
+};
+
+//=============================================================================
+static
+KSDATARANGE MicArrayPinDataRangesBridge[] =
+{
+ {
+ sizeof(KSDATARANGE),
+ 0,
+ 0,
+ 0,
+ STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
+ STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
+ }
+};
+
+static
+PKSDATARANGE MicArrayPinDataRangePointersBridge[] =
+{
+ &MicArrayPinDataRangesBridge[0]
+};
+
+//=============================================================================
+static
+PCPIN_DESCRIPTOR MicArrayWaveMiniportPins[] =
+{
+ // Wave In Bridge Pin (Capture - From Topology) KSPIN_WAVE_BRIDGE
+ {
+ 0,
+ 0,
+ 0,
+ NULL,
+ {
+ 0,
+ NULL,
+ 0,
+ NULL,
+ SIZEOF_ARRAY(MicArrayPinDataRangePointersBridge),
+ MicArrayPinDataRangePointersBridge,
+ KSPIN_DATAFLOW_IN,
+ KSPIN_COMMUNICATION_NONE,
+ &KSCATEGORY_AUDIO,
+ NULL,
+ 0
+ }
+ },
+ // Wave In Streaming Pin (Capture) KSPIN_WAVE_HOST
+ {
+ MICARRAY_MAX_INPUT_STREAMS,
+ MICARRAY_MAX_INPUT_STREAMS,
+ 0,
+ NULL,
+ {
+ 0,
+ NULL,
+ 0,
+ NULL,
+ SIZEOF_ARRAY(MicArrayPinDataRangePointersStream),
+ MicArrayPinDataRangePointersStream,
+ KSPIN_DATAFLOW_OUT,
+ KSPIN_COMMUNICATION_SINK,
+ &KSCATEGORY_AUDIO,
+ &KSAUDFNAME_RECORDING_CONTROL,
+ 0
+ }
+ }
+};
+
+//=============================================================================
+static
+PCNODE_DESCRIPTOR MicArrayWaveMiniportNodes[] =
+{
+ // KSNODE_WAVE_ADC
+ {
+ 0, // Flags
+ NULL, // AutomationTable
+ &KSNODETYPE_ADC, // Type
+ NULL // Name
+ }
+};
+
+//=============================================================================
+static
+PCCONNECTION_DESCRIPTOR MicArrayWaveMiniportConnections[] =
+{
+ { PCFILTER_NODE, KSPIN_WAVE_BRIDGE, KSNODE_WAVE_ADC, 1 },
+ { KSNODE_WAVE_ADC, 0, PCFILTER_NODE, KSPIN_WAVEIN_HOST },
+};
+
+//=============================================================================
+
+static
+SIMPLEAUDIOSAMPLE_PROPERTY_ITEM PropertiesMicArrayWaveFilter[] =
+{
+ {
+ {
+ &KSPROPSETID_General,
+ KSPROPERTY_GENERAL_COMPONENTID,
+ KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_WaveFilter,
+ },
+ 0,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0
+ },
+ {
+ {
+ &KSPROPSETID_Pin,
+ KSPROPERTY_PIN_PROPOSEDATAFORMAT,
+ KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_WaveFilter,
+ },
+ 0,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0
+ },
+ {
+ {
+ &KSPROPSETID_Pin,
+ KSPROPERTY_PIN_PROPOSEDATAFORMAT2,
+ KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_WaveFilter,
+ },
+ 0,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0
+ },
+};
+
+DEFINE_PCAUTOMATION_TABLE_PROP(AutomationMicArrayWaveFilter, PropertiesMicArrayWaveFilter);
+
+//=============================================================================
+static
+PCFILTER_DESCRIPTOR MicArrayWaveMiniportFilterDescriptor =
+{
+ 0, // Version
+ &AutomationMicArrayWaveFilter, // AutomationTable
+ sizeof(PCPIN_DESCRIPTOR), // PinSize
+ SIZEOF_ARRAY(MicArrayWaveMiniportPins), // PinCount
+ MicArrayWaveMiniportPins, // Pins
+ sizeof(PCNODE_DESCRIPTOR), // NodeSize
+ SIZEOF_ARRAY(MicArrayWaveMiniportNodes), // NodeCount
+ MicArrayWaveMiniportNodes, // Nodes
+ SIZEOF_ARRAY(MicArrayWaveMiniportConnections), // ConnectionCount
+ MicArrayWaveMiniportConnections, // Connections
+ 0, // CategoryCount
+ NULL // Categories - use defaults (audio, render, capture)
+};
+
+#endif // _SIMPLEAUDIOSAMPLE_MICARRAYWAVTABLE_H_
diff --git a/audio/simpleaudiosample/Source/Filters/minipairs.h b/audio/simpleaudiosample/Source/Filters/minipairs.h
new file mode 100644
index 00000000..b7d8950f
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Filters/minipairs.h
@@ -0,0 +1,177 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ minipairs.h
+
+Abstract:
+
+ Local audio endpoint filter definitions.
+--*/
+
+#ifndef _SIMPLEAUDIOSAMPLE_MINIPAIRS_H_
+#define _SIMPLEAUDIOSAMPLE_MINIPAIRS_H_
+
+#include "speakertopo.h"
+#include "speakertoptable.h"
+#include "speakerwavtable.h"
+
+#include "micarraytopo.h"
+#include "micarray1toptable.h"
+#include "micarraywavtable.h"
+
+
+NTSTATUS
+CreateMiniportWaveRTSimpleAudioSample
+(
+ _Out_ PUNKNOWN *,
+ _In_ REFCLSID,
+ _In_opt_ PUNKNOWN,
+ _In_ POOL_FLAGS,
+ _In_ PUNKNOWN,
+ _In_opt_ PVOID,
+ _In_ PENDPOINT_MINIPAIR
+);
+
+NTSTATUS
+CreateMiniportTopologySimpleAudioSample
+(
+ _Out_ PUNKNOWN *,
+ _In_ REFCLSID,
+ _In_opt_ PUNKNOWN,
+ _In_ POOL_FLAGS,
+ _In_ PUNKNOWN,
+ _In_opt_ PVOID,
+ _In_ PENDPOINT_MINIPAIR
+);
+
+//
+// Render miniports.
+//
+
+/*********************************************************************
+* Topology/Wave bridge connection for speaker (internal) *
+* *
+* +------+ +------+ *
+* | Wave | | Topo | *
+* | | | | *
+* System --->|0 1|--------------->|0 1|---> Line Out *
+* | | | | *
+* +------+ +------+ *
+*********************************************************************/
+static
+PHYSICALCONNECTIONTABLE SpeakerTopologyPhysicalConnections[] =
+{
+ {
+ KSPIN_TOPO_WAVEOUT_SOURCE, // TopologyIn
+ KSPIN_WAVE_RENDER3_SOURCE, // WaveOut
+ CONNECTIONTYPE_WAVE_OUTPUT
+ }
+};
+
+static
+ENDPOINT_MINIPAIR SpeakerMiniports =
+{
+ eSpeakerDevice,
+ L"TopologySpeaker", // make sure this or the template name matches with KSNAME_TopologySpeaker in the inf's [Strings] section
+ NULL, // optional template name
+ CreateMiniportTopologySimpleAudioSample,
+ &SpeakerTopoMiniportFilterDescriptor,
+ 0, NULL, // Interface properties
+ L"WaveSpeaker", // make sure this or the template name matches with KSNAME_WaveSpeaker in the inf's [Strings] section
+ NULL, // optional template name
+ CreateMiniportWaveRTSimpleAudioSample,
+ &SpeakerWaveMiniportFilterDescriptor,
+ 0, // Interface properties
+ NULL,
+ SPEAKER_DEVICE_MAX_CHANNELS,
+ SpeakerPinDeviceFormatsAndModes,
+ SIZEOF_ARRAY(SpeakerPinDeviceFormatsAndModes),
+ SpeakerTopologyPhysicalConnections,
+ SIZEOF_ARRAY(SpeakerTopologyPhysicalConnections),
+ ENDPOINT_NO_FLAGS,
+};
+
+//
+// Capture miniports.
+//
+
+/*********************************************************************
+* Topology/Wave bridge connection for mic array 1 (front) *
+* *
+* +------+ +------+ *
+* | Topo | | Wave | *
+* | | | | *
+* Mic in --->|0 1|===>|0 1|---> Capture Host Pin *
+* | | | | *
+* +------+ +------+ *
+*********************************************************************/
+static
+PHYSICALCONNECTIONTABLE MicArray1TopologyPhysicalConnections[] =
+{
+ {
+ KSPIN_TOPO_BRIDGE, // TopologyOut
+ KSPIN_WAVE_BRIDGE, // WaveIn
+ CONNECTIONTYPE_TOPOLOGY_OUTPUT
+ }
+};
+
+static
+ENDPOINT_MINIPAIR MicArray1Miniports =
+{
+ eMicArrayDevice1,
+ L"TopologyMicArray1", // make sure this or the template name matches with KSNAME_TopologyMicArray1 in the inf's [Strings] section
+ NULL, // optional template name
+ CreateMicArrayMiniportTopology,
+ &MicArray1TopoMiniportFilterDescriptor,
+ 0, NULL, // Interface properties
+ L"WaveMicArray1", // make sure this or the tempalte name matches with KSNAME_WaveMicArray1 in the inf's [Strings] section
+ NULL, // optional template name
+ CreateMiniportWaveRTSimpleAudioSample,
+ &MicArrayWaveMiniportFilterDescriptor,
+ 0, // Interface properties
+ NULL,
+ MICARRAY_DEVICE_MAX_CHANNELS,
+ MicArrayPinDeviceFormatsAndModes,
+ SIZEOF_ARRAY(MicArrayPinDeviceFormatsAndModes),
+ MicArray1TopologyPhysicalConnections,
+ SIZEOF_ARRAY(MicArray1TopologyPhysicalConnections),
+ ENDPOINT_NO_FLAGS,
+};
+
+
+//=============================================================================
+//
+// Render miniport pairs. NOTE: the split of render and capture is arbitrary and
+// unnessary, this array could contain capture endpoints.
+//
+static
+PENDPOINT_MINIPAIR g_RenderEndpoints[] =
+{
+ &SpeakerMiniports,
+};
+
+#define g_cRenderEndpoints (SIZEOF_ARRAY(g_RenderEndpoints))
+
+//=============================================================================
+//
+// Capture miniport pairs. NOTE: the split of render and capture is arbitrary and
+// unnessary, this array could contain render endpoints.
+//
+static
+PENDPOINT_MINIPAIR g_CaptureEndpoints[] =
+{
+ &MicArray1Miniports,
+};
+
+#define g_cCaptureEndpoints (SIZEOF_ARRAY(g_CaptureEndpoints))
+
+//=============================================================================
+//
+// Total miniports = # endpoints * 2 (topology + wave).
+//
+#define g_MaxMiniports ((g_cRenderEndpoints + g_cCaptureEndpoints) * 2)
+
+#endif // _SIMPLEAUDIOSAMPLE_MINIPAIRS_H_
diff --git a/audio/simpleaudiosample/Source/Filters/speakertopo.cpp b/audio/simpleaudiosample/Source/Filters/speakertopo.cpp
new file mode 100644
index 00000000..d1635efa
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Filters/speakertopo.cpp
@@ -0,0 +1,118 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ speakertopo.cpp
+
+Abstract:
+
+ Implementation of topology miniport for the speaker (internal).
+--*/
+
+#pragma warning (disable : 4127)
+
+#include "definitions.h"
+#include "endpoints.h"
+#include "mintopo.h"
+#include "speakertopo.h"
+#include "speakertoptable.h"
+
+
+#pragma code_seg("PAGE")
+//=============================================================================
+NTSTATUS
+PropertyHandler_SpeakerTopoFilter
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Redirects property request to miniport object
+
+Arguments:
+
+ PropertyRequest -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(PropertyRequest);
+
+ DPF_ENTER(("[PropertyHandler_SpeakerTopoFilter]"));
+
+ // PropertryRequest structure is filled by portcls.
+ // MajorTarget is a pointer to miniport object for miniports.
+ //
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ PCMiniportTopology pMiniport = (PCMiniportTopology)PropertyRequest->MajorTarget;
+
+ if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Jack))
+ {
+ if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION)
+ {
+ ntStatus = pMiniport->PropertyHandlerJackDescription(
+ PropertyRequest,
+ ARRAYSIZE(SpeakerJackDescriptions),
+ SpeakerJackDescriptions
+ );
+ }
+ else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION2)
+ {
+ ntStatus = pMiniport->PropertyHandlerJackDescription2(
+ PropertyRequest,
+ ARRAYSIZE(SpeakerJackDescriptions),
+ SpeakerJackDescriptions,
+ 0 // jack capabilities
+ );
+ }
+ }
+
+ return ntStatus;
+} // PropertyHandler_SpeakerTopoFilter
+
+//=============================================================================
+NTSTATUS
+PropertyHandler_SpeakerTopology
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Redirects property request to miniport object
+
+Arguments:
+
+ PropertyRequest -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(PropertyRequest);
+
+ DPF_ENTER(("[PropertyHandler_SpeakerTopology]"));
+
+ // PropertryRequest structure is filled by portcls.
+ // MajorTarget is a pointer to miniport object for miniports.
+ //
+ PCMiniportTopology pMiniport = (PCMiniportTopology)PropertyRequest->MajorTarget;
+
+ return pMiniport->PropertyHandlerGeneric(PropertyRequest);
+} // PropertyHandler_SpeakerTopology
+
+#pragma code_seg()
diff --git a/audio/simpleaudiosample/Source/Filters/speakertopo.h b/audio/simpleaudiosample/Source/Filters/speakertopo.h
new file mode 100644
index 00000000..0eff1ebb
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Filters/speakertopo.h
@@ -0,0 +1,22 @@
+
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ speakertopo.h
+
+Abstract:
+
+ Declaration of topology miniport for the speaker (internal).
+--*/
+
+#ifndef _SIMPLEAUDIOSAMPLE_SPEAKERTOPO_H_
+#define _SIMPLEAUDIOSAMPLE_SPEAKERTOPO_H_
+
+NTSTATUS PropertyHandler_SpeakerTopoFilter(_In_ PPCPROPERTY_REQUEST PropertyRequest);
+
+NTSTATUS PropertyHandler_SpeakerTopology(_In_ PPCPROPERTY_REQUEST PropertyRequest);
+
+#endif // _SIMPLEAUDIOSAMPLE_SPEAKERTOPO_H_
diff --git a/audio/simpleaudiosample/Source/Filters/speakertoptable.h b/audio/simpleaudiosample/Source/Filters/speakertoptable.h
new file mode 100644
index 00000000..1b046d96
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Filters/speakertoptable.h
@@ -0,0 +1,206 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ speakertoptable.h
+
+Abstract:
+
+ Declaration of topology tables.
+--*/
+
+#ifndef _SIMPLEAUDIOSAMPLE_SPEAKERTOPTABLE_H_
+#define _SIMPLEAUDIOSAMPLE_SPEAKERTOPTABLE_H_
+
+//=============================================================================
+static
+KSDATARANGE SpeakerTopoPinDataRangesBridge[] =
+{
+ {
+ sizeof(KSDATARANGE),
+ 0,
+ 0,
+ 0,
+ STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
+ STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
+ }
+};
+
+//=============================================================================
+static
+PKSDATARANGE SpeakerTopoPinDataRangePointersBridge[] =
+{
+ &SpeakerTopoPinDataRangesBridge[0]
+};
+
+//=============================================================================
+static
+PCPIN_DESCRIPTOR SpeakerTopoMiniportPins[] =
+{
+ // KSPIN_TOPO_WAVEOUT_SOURCE
+ {
+ 0,
+ 0,
+ 0, // InstanceCount
+ NULL, // AutomationTable
+ { // KsPinDescriptor
+ 0, // InterfacesCount
+ NULL, // Interfaces
+ 0, // MediumsCount
+ NULL, // Mediums
+ SIZEOF_ARRAY(SpeakerTopoPinDataRangePointersBridge),// DataRangesCount
+ SpeakerTopoPinDataRangePointersBridge, // DataRanges
+ KSPIN_DATAFLOW_IN, // DataFlow
+ KSPIN_COMMUNICATION_NONE, // Communication
+ &KSCATEGORY_AUDIO, // Category
+ NULL, // Name
+ 0 // Reserved
+ }
+ },
+ // KSPIN_TOPO_LINEOUT_DEST
+ {
+ 0,
+ 0,
+ 0, // InstanceCount
+ NULL, // AutomationTable
+ { // KsPinDescriptor
+ 0, // InterfacesCount
+ NULL, // Interfaces
+ 0, // MediumsCount
+ NULL, // Mediums
+ SIZEOF_ARRAY(SpeakerTopoPinDataRangePointersBridge),// DataRangesCount
+ SpeakerTopoPinDataRangePointersBridge, // DataRanges
+ KSPIN_DATAFLOW_OUT, // DataFlow
+ KSPIN_COMMUNICATION_NONE, // Communication
+ &KSNODETYPE_SPEAKER, // Category
+ NULL, // Name
+ 0 // Reserved
+ }
+ }
+};
+
+//=============================================================================
+static
+KSJACK_DESCRIPTION SpeakerJackDescBridge =
+{
+ KSAUDIO_SPEAKER_STEREO,
+ 0xB3C98C, // Color spec for green
+ eConnTypeUnknown,
+ eGeoLocFront,
+ eGenLocPrimaryBox,
+ ePortConnIntegratedDevice,
+ TRUE
+};
+
+// Only return a KSJACK_DESCRIPTION for the physical bridge pin.
+static
+PKSJACK_DESCRIPTION SpeakerJackDescriptions[] =
+{
+ NULL,
+ &SpeakerJackDescBridge
+};
+
+//=============================================================================
+static
+PCPROPERTY_ITEM SpeakerPropertiesVolume[] =
+{
+ {
+ &KSPROPSETID_Audio,
+ KSPROPERTY_AUDIO_VOLUMELEVEL,
+ KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_SpeakerTopology
+ }
+};
+
+DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSpeakerVolume, SpeakerPropertiesVolume);
+
+//=============================================================================
+static
+PCPROPERTY_ITEM SpeakerPropertiesMute[] =
+{
+ {
+ &KSPROPSETID_Audio,
+ KSPROPERTY_AUDIO_MUTE,
+ KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_SpeakerTopology
+ }
+};
+
+DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSpeakerMute, SpeakerPropertiesMute);
+
+//=============================================================================
+static
+PCNODE_DESCRIPTOR SpeakerTopologyNodes[] =
+{
+ // KSNODE_TOPO_VOLUME
+ {
+ 0, // Flags
+ &AutomationSpeakerVolume, // AutomationTable
+ &KSNODETYPE_VOLUME, // Type
+ &KSAUDFNAME_MASTER_VOLUME // Name
+ },
+ // KSNODE_TOPO_MUTE
+ {
+ 0, // Flags
+ &AutomationSpeakerMute, // AutomationTable
+ &KSNODETYPE_MUTE, // Type
+ &KSAUDFNAME_MASTER_MUTE // Name
+ }
+};
+
+C_ASSERT(KSNODE_TOPO_VOLUME == 0);
+C_ASSERT(KSNODE_TOPO_MUTE == 1);
+
+static
+PCCONNECTION_DESCRIPTOR SpeakerTopoMiniportConnections[] =
+{
+ // FromNode, FromPin, ToNode, ToPin
+ { PCFILTER_NODE, KSPIN_TOPO_WAVEOUT_SOURCE, KSNODE_TOPO_VOLUME, 1 },
+ { KSNODE_TOPO_VOLUME, 0, KSNODE_TOPO_MUTE, 1 },
+ { KSNODE_TOPO_MUTE, 0, PCFILTER_NODE, KSPIN_TOPO_LINEOUT_DEST }
+};
+
+//=============================================================================
+static
+PCPROPERTY_ITEM PropertiesSpeakerTopoFilter[] =
+{
+ {
+ &KSPROPSETID_Jack,
+ KSPROPERTY_JACK_DESCRIPTION,
+ KSPROPERTY_TYPE_GET |
+ KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_SpeakerTopoFilter
+ },
+ {
+ &KSPROPSETID_Jack,
+ KSPROPERTY_JACK_DESCRIPTION2,
+ KSPROPERTY_TYPE_GET |
+ KSPROPERTY_TYPE_BASICSUPPORT,
+ PropertyHandler_SpeakerTopoFilter
+ }
+};
+
+DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSpeakerTopoFilter, PropertiesSpeakerTopoFilter);
+
+//=============================================================================
+static
+PCFILTER_DESCRIPTOR SpeakerTopoMiniportFilterDescriptor =
+{
+ 0, // Version
+ &AutomationSpeakerTopoFilter, // AutomationTable
+ sizeof(PCPIN_DESCRIPTOR), // PinSize
+ SIZEOF_ARRAY(SpeakerTopoMiniportPins), // PinCount
+ SpeakerTopoMiniportPins, // Pins
+ sizeof(PCNODE_DESCRIPTOR), // NodeSize
+ SIZEOF_ARRAY(SpeakerTopologyNodes), // NodeCount
+ SpeakerTopologyNodes, // Nodes
+ SIZEOF_ARRAY(SpeakerTopoMiniportConnections), // ConnectionCount
+ SpeakerTopoMiniportConnections, // Connections
+ 0, // CategoryCount
+ NULL // Categories
+};
+
+#endif // _SIMPLEAUDIOSAMPLE_SPEAKERTOPTABLE_H_
diff --git a/audio/sysvad/PhoneAudioSample/FMWavTable.h b/audio/simpleaudiosample/Source/Filters/speakerwavtable.h
index 6ef9fb46..e67a673c 100644
--- a/audio/sysvad/PhoneAudioSample/FMWavTable.h
+++ b/audio/simpleaudiosample/Source/Filters/speakerwavtable.h
@@ -4,34 +4,35 @@ Copyright (c) Microsoft Corporation All Rights Reserved
Module Name:
- fmwavtable.h
+ speakerwavtable.h
Abstract:
- Declaration of wave miniport tables for the fm endpoint.
-
- Note: the FM in this sample shows how to do h/w loopback
- for non-offloaded devices.
-
+ Declaration of wave miniport tables for the render endpoints.
--*/
-#ifndef _SYSVAD_FMWAVTABLE_H_
-#define _SYSVAD_FMWAVTABLE_H_
+#ifndef _SIMPLEAUDIOSAMPLE_SPEAKERWAVTABLE_H_
+#define _SIMPLEAUDIOSAMPLE_SPEAKERWAVTABLE_H_
+// To keep the code simple assume device supports only 48KHz, 16-bit, stereo (PCM and NON-PCM)
-#define FMRX_DEVICE_MAX_CHANNELS 2 // Max Channels.
+#define SPEAKER_DEVICE_MAX_CHANNELS 2 // Max Channels.
-#define FMRX_MAX_CHANNELS 2 // Max Channels.
-#define FMRX_MIN_BITS_PER_SAMPLE 16 // Min Bits Per Sample
-#define FMRX_MAX_BITS_PER_SAMPLE 16 // Max Bits Per Sample
-#define FMRX_MIN_SAMPLE_RATE 48000 // Min Sample Rate
-#define FMRX_MAX_SAMPLE_RATE 48000 // Max Sample Rate
-#define FMRX_MAX_INPUT_SYSTEM_STREAMS 1
+#define SPEAKER_HOST_MAX_CHANNELS 2 // Max Channels.
+#define SPEAKER_HOST_MIN_BITS_PER_SAMPLE 16 // Min Bits Per Sample
+#define SPEAKER_HOST_MAX_BITS_PER_SAMPLE 16 // Max Bits Per Sample
+#define SPEAKER_HOST_MIN_SAMPLE_RATE 48000 // Min Sample Rate
+#define SPEAKER_HOST_MAX_SAMPLE_RATE 48000 // Max Sample Rate
+//
+// Max # of pin instances.
+//
+#define SPEAKER_MAX_INPUT_SYSTEM_STREAMS 1
//=============================================================================
+
static
-KSDATAFORMAT_WAVEFORMATEXTENSIBLE FmRxPinSupportedDeviceFormats[] =
+KSDATAFORMAT_WAVEFORMATEXTENSIBLE SpeakerHostPinSupportedDeviceFormats[] =
{
{ // 0
{
@@ -64,40 +65,40 @@ KSDATAFORMAT_WAVEFORMATEXTENSIBLE FmRxPinSupportedDeviceFormats[] =
// Supported modes (only on streaming pins).
//
static
-MODE_AND_DEFAULT_FORMAT FmRxPinSupportedDeviceModes[] =
+MODE_AND_DEFAULT_FORMAT SpeakerHostPinSupportedDeviceModes[] =
{
{
- STATIC_AUDIO_SIGNALPROCESSINGMODE_RAW,
- &FmRxPinSupportedDeviceFormats[SIZEOF_ARRAY(FmRxPinSupportedDeviceFormats) - 1].DataFormat
+ STATIC_AUDIO_SIGNALPROCESSINGMODE_DEFAULT,
+ &SpeakerHostPinSupportedDeviceFormats[0].DataFormat // 48KHz
}
};
-//=============================================================================
+//
// The entries here must follow the same order as the filter's pin
// descriptor array.
//
-static
-PIN_DEVICE_FORMATS_AND_MODES FmRxPinDeviceFormatsAndModes[] =
+static
+PIN_DEVICE_FORMATS_AND_MODES SpeakerPinDeviceFormatsAndModes[] =
{
- { // RX
- SystemCapturePin,
- FmRxPinSupportedDeviceFormats,
- SIZEOF_ARRAY(FmRxPinSupportedDeviceFormats),
- FmRxPinSupportedDeviceModes,
- SIZEOF_ARRAY(FmRxPinSupportedDeviceModes)
+ {
+ SystemRenderPin,
+ SpeakerHostPinSupportedDeviceFormats,
+ SIZEOF_ARRAY(SpeakerHostPinSupportedDeviceFormats),
+ SpeakerHostPinSupportedDeviceModes,
+ SIZEOF_ARRAY(SpeakerHostPinSupportedDeviceModes)
},
{
BridgePin,
NULL,
0,
NULL,
- 0,
- },
+ 0
+ }
};
//=============================================================================
static
-KSDATARANGE_AUDIO FmPinDataRangesStream[] =
+KSDATARANGE_AUDIO SpeakerPinDataRangesStream[] =
{
{ // 0
{
@@ -109,24 +110,24 @@ KSDATARANGE_AUDIO FmPinDataRangesStream[] =
STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
},
- FMRX_MAX_CHANNELS,
- FMRX_MIN_BITS_PER_SAMPLE,
- FMRX_MAX_BITS_PER_SAMPLE,
- FMRX_MIN_SAMPLE_RATE,
- FMRX_MAX_SAMPLE_RATE
- },
+ SPEAKER_HOST_MAX_CHANNELS,
+ SPEAKER_HOST_MIN_BITS_PER_SAMPLE,
+ SPEAKER_HOST_MAX_BITS_PER_SAMPLE,
+ SPEAKER_HOST_MIN_SAMPLE_RATE,
+ SPEAKER_HOST_MAX_SAMPLE_RATE
+ }
};
static
-PKSDATARANGE FmPinDataRangePointersStream[] =
+PKSDATARANGE SpeakerPinDataRangePointersStream[] =
{
- PKSDATARANGE(&FmPinDataRangesStream[0]),
- PKSDATARANGE(&PinDataRangeAttributeList)
+ PKSDATARANGE(&SpeakerPinDataRangesStream[0]),
+ PKSDATARANGE(&PinDataRangeAttributeList),
};
//=============================================================================
static
-KSDATARANGE FmPinDataRangesBridge[] =
+KSDATARANGE SpeakerPinDataRangesBridge[] =
{
{
sizeof(KSDATARANGE),
@@ -140,37 +141,36 @@ KSDATARANGE FmPinDataRangesBridge[] =
};
static
-PKSDATARANGE FmPinDataRangePointersBridge[] =
+PKSDATARANGE SpeakerPinDataRangePointersBridge[] =
{
- &FmPinDataRangesBridge[0]
+ &SpeakerPinDataRangesBridge[0]
};
-
//=============================================================================
static
-PCPIN_DESCRIPTOR FmWaveMiniportPins[] =
+PCPIN_DESCRIPTOR SpeakerWaveMiniportPins[] =
{
- // Wave In Streaming Pin KSPIN_WAVE_FMRX
+ // Wave Out Streaming Pin (Renderer) KSPIN_WAVE_RENDER3_SINK_SYSTEM
{
- FMRX_MAX_INPUT_SYSTEM_STREAMS,
- FMRX_MAX_INPUT_SYSTEM_STREAMS,
+ SPEAKER_MAX_INPUT_SYSTEM_STREAMS,
+ SPEAKER_MAX_INPUT_SYSTEM_STREAMS,
0,
- NULL,
+ NULL, // AutomationTable
{
0,
NULL,
0,
NULL,
- SIZEOF_ARRAY(FmPinDataRangePointersStream),
- FmPinDataRangePointersStream,
- KSPIN_DATAFLOW_OUT,
+ SIZEOF_ARRAY(SpeakerPinDataRangePointersStream),
+ SpeakerPinDataRangePointersStream,
+ KSPIN_DATAFLOW_IN,
KSPIN_COMMUNICATION_SINK,
&KSCATEGORY_AUDIO,
NULL,
0
}
},
- // Wave In Bridge Pin KSPIN_WAVE_FMRX_BRIDGE
+ // Wave Out Bridge Pin (Renderer) KSPIN_WAVE_RENDER3_SOURCE
{
0,
0,
@@ -181,9 +181,9 @@ PCPIN_DESCRIPTOR FmWaveMiniportPins[] =
NULL,
0,
NULL,
- SIZEOF_ARRAY(FmPinDataRangePointersBridge),
- FmPinDataRangePointersBridge,
- KSPIN_DATAFLOW_IN,
+ SIZEOF_ARRAY(SpeakerPinDataRangePointersBridge),
+ SpeakerPinDataRangePointersBridge,
+ KSPIN_DATAFLOW_OUT,
KSPIN_COMMUNICATION_NONE,
&KSCATEGORY_AUDIO,
NULL,
@@ -194,21 +194,20 @@ PCPIN_DESCRIPTOR FmWaveMiniportPins[] =
//=============================================================================
//
-// -----
-// | |
-// FM RX bridge pin 1 -->| |--> 0 FM RX pin
-// | |
-// -----
-
+// ----------------------------
+// | |
+// Host Pin 0-->| |--> 1 KSPIN_WAVE_RENDER3_SOURCE
+// | |
+// ----------------------------
static
-PCCONNECTION_DESCRIPTOR FmWaveMiniportConnections[] =
+PCCONNECTION_DESCRIPTOR SpeakerWaveMiniportConnections[] =
{
- { PCFILTER_NODE, KSPIN_WAVE_FMRX_BRIDGE, PCFILTER_NODE, KSPIN_WAVE_FMRX },
+ { PCFILTER_NODE, KSPIN_WAVE_RENDER3_SINK_SYSTEM, PCFILTER_NODE, KSPIN_WAVE_RENDER3_SOURCE }
};
//=============================================================================
static
-PCPROPERTY_ITEM PropertiesFmWaveFilter[] =
+PCPROPERTY_ITEM PropertiesSpeakerWaveFilter[] =
{
{
&KSPROPSETID_Pin,
@@ -221,34 +220,27 @@ PCPROPERTY_ITEM PropertiesFmWaveFilter[] =
KSPROPERTY_PIN_PROPOSEDATAFORMAT2,
KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
PropertyHandler_WaveFilter
- },
- {
- &KSPROPSETID_FMRXControl,
- KSPROPERTY_FMRX_STATE,
- KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_FmRxWaveFilter
}
};
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationFmWaveFilter, PropertiesFmWaveFilter);
+DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSpeakerWaveFilter, PropertiesSpeakerWaveFilter);
//=============================================================================
static
-PCFILTER_DESCRIPTOR FmWaveMiniportFilterDescriptor =
+PCFILTER_DESCRIPTOR SpeakerWaveMiniportFilterDescriptor =
{
0, // Version
- &AutomationFmWaveFilter, // AutomationTable
+ &AutomationSpeakerWaveFilter, // AutomationTable
sizeof(PCPIN_DESCRIPTOR), // PinSize
- SIZEOF_ARRAY(FmWaveMiniportPins), // PinCount
- FmWaveMiniportPins, // Pins
+ SIZEOF_ARRAY(SpeakerWaveMiniportPins), // PinCount
+ SpeakerWaveMiniportPins, // Pins
sizeof(PCNODE_DESCRIPTOR), // NodeSize
0, // NodeCount
NULL, // Nodes
- SIZEOF_ARRAY(FmWaveMiniportConnections), // ConnectionCount
- FmWaveMiniportConnections, // Connections
+ SIZEOF_ARRAY(SpeakerWaveMiniportConnections), // ConnectionCount
+ SpeakerWaveMiniportConnections, // Connections
0, // CategoryCount
NULL // Categories - use defaults (audio, render, capture)
};
-#endif // _SYSVAD_FMWAVTABLE_H_
-
+#endif // _SIMPLEAUDIOSAMPLE_SPEAKERWAVTABLE_H_
diff --git a/audio/simpleaudiosample/Source/Inc/Inc.vcxproj b/audio/simpleaudiosample/Source/Inc/Inc.vcxproj
new file mode 100644
index 00000000..ab768d84
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Inc/Inc.vcxproj
@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|ARM64">
+ <Configuration>Debug</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|ARM64">
+ <Configuration>Release</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{4B664BA5-057A-41B8-B365-2C99065C4DFA}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{F51739CE-5253-42B5-9191-57F28B5842C6}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>Inc</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <TargetName>Inc</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>Inc</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <TargetName>Inc</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>Inc</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>Inc</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>
diff --git a/audio/simpleaudiosample/Source/Inc/Inc.vcxproj.Filters b/audio/simpleaudiosample/Source/Inc/Inc.vcxproj.Filters
new file mode 100644
index 00000000..353662af
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Inc/Inc.vcxproj.Filters
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{54BE0AAC-642F-4D50-80D1-CA3C4BB4BB4C}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{6A00B9EC-DB03-4D51-B351-60DE9C0C51A1}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{887357BD-50C0-40E6-85E8-87E0F45862DB}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="*.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project>
diff --git a/audio/simpleaudiosample/Source/Inc/NewDelete.h b/audio/simpleaudiosample/Source/Inc/NewDelete.h
new file mode 100644
index 00000000..ebeab037
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Inc/NewDelete.h
@@ -0,0 +1,104 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+NewDelete.h
+
+Abstract:
+
+Declaration of placement new and delete operators.
+--*/
+#pragma once
+
+#ifdef _NEW_DELETE_OPERATORS_
+
+/*****************************************************************************
+* Functions
+*/
+
+/*****************************************************************************
+* ::new()
+*****************************************************************************
+* New function for creating objects with a specified allocation tag and
+* pool type
+*/
+PVOID operator new
+(
+ size_t iSize,
+ POOL_FLAGS poolFlags,
+ ULONG tag
+);
+
+
+/*****************************************************************************
+* ::new()
+*****************************************************************************
+* New function for creating objects with a specified pool type.
+*/
+PVOID operator new
+(
+ size_t iSize,
+ POOL_FLAGS poolFlags
+);
+
+
+/*****************************************************************************
+* ::delete()
+*****************************************************************************
+* Delete with tag function.
+*/
+void __cdecl operator delete
+(
+ PVOID pVoid,
+ ULONG tag
+);
+
+
+/*****************************************************************************
+* ::delete()
+*****************************************************************************
+* Sized Delete function.
+*/
+void __cdecl operator delete
+(
+ _Pre_maybenull_ __drv_freesMem(Mem) PVOID pVoid,
+ _In_ size_t cbSize
+);
+
+
+/*****************************************************************************
+* ::delete()
+*****************************************************************************
+* Basic Delete function.
+*/
+void __cdecl operator delete
+(
+ PVOID pVoid
+);
+
+
+/*****************************************************************************
+* ::delete()
+*****************************************************************************
+* Sized Array Delete function.
+*/
+void __cdecl operator delete[]
+(
+ _Pre_maybenull_ __drv_freesMem(Mem) PVOID pVoid,
+ _In_ size_t cbSize
+);
+
+
+/*****************************************************************************
+* ::delete()
+*****************************************************************************
+* Array Delete function.
+*/
+void __cdecl operator delete[]
+(
+ _Pre_maybenull_ __drv_freesMem(Mem) PVOID pVoid
+);
+
+#endif//_NEW_DELETE_OPERATORS_
diff --git a/audio/simpleaudiosample/Source/Inc/basetopo.h b/audio/simpleaudiosample/Source/Inc/basetopo.h
new file mode 100644
index 00000000..a893aa3e
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Inc/basetopo.h
@@ -0,0 +1,96 @@
+
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ basetopo.h
+
+Abstract:
+
+ Declaration of topology miniport.
+--*/
+
+#ifndef _SIMPLEAUDIOSAMPLE_BASETOPO_H_
+#define _SIMPLEAUDIOSAMPLE_BASETOPO_H_
+
+//=============================================================================
+// Classes
+//=============================================================================
+
+///////////////////////////////////////////////////////////////////////////////
+// CMiniportTopologySimpleAudioSample
+//
+
+class CMiniportTopologySimpleAudioSample
+{
+ protected:
+ PADAPTERCOMMON m_AdapterCommon; // Adapter common object.
+ PPCFILTER_DESCRIPTOR m_FilterDescriptor; // Filter descriptor.
+ PPORTEVENTS m_PortEvents; // Event interface.
+ USHORT m_DeviceMaxChannels; // Max device channels.
+
+ public:
+ CMiniportTopologySimpleAudioSample(
+ _In_ PCFILTER_DESCRIPTOR *FilterDesc,
+ _In_ USHORT DeviceMaxChannels
+ );
+
+ ~CMiniportTopologySimpleAudioSample();
+
+ NTSTATUS GetDescription
+ (
+ _Out_ PPCFILTER_DESCRIPTOR * Description
+ );
+
+ NTSTATUS DataRangeIntersection
+ (
+ _In_ ULONG PinId,
+ _In_ PKSDATARANGE ClientDataRange,
+ _In_ PKSDATARANGE MyDataRange,
+ _In_ ULONG OutputBufferLength,
+ _Out_writes_bytes_to_opt_(OutputBufferLength, *ResultantFormatLength)
+ PVOID ResultantFormat OPTIONAL,
+ _Out_ PULONG ResultantFormatLength
+ );
+
+ NTSTATUS Init
+ (
+ _In_ PUNKNOWN UnknownAdapter,
+ _In_ PPORTTOPOLOGY Port_
+ );
+
+ // PropertyHandlers.
+ NTSTATUS PropertyHandlerGeneric
+ (
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+ );
+
+ NTSTATUS PropertyHandlerMuxSource
+ (
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+ );
+
+ NTSTATUS PropertyHandlerDevSpecific
+ (
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+ );
+
+ VOID AddEventToEventList
+ (
+ _In_ PKSEVENT_ENTRY EventEntry
+ );
+
+ VOID GenerateEventList
+ (
+ _In_opt_ GUID *Set,
+ _In_ ULONG EventId,
+ _In_ BOOL PinEvent,
+ _In_ ULONG PinId,
+ _In_ BOOL NodeEvent,
+ _In_ ULONG NodeId
+ );
+};
+
+#endif
diff --git a/audio/simpleaudiosample/Source/Inc/common.h b/audio/simpleaudiosample/Source/Inc/common.h
new file mode 100644
index 00000000..2d2db7db
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Inc/common.h
@@ -0,0 +1,477 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ Common.h
+
+Abstract:
+
+ CAdapterCommon class declaration.
+--*/
+
+#ifndef _SIMPLEAUDIOSAMPLE_COMMON_H_
+#define _SIMPLEAUDIOSAMPLE_COMMON_H_
+
+#define HNSTIME_PER_MILLISECOND 10000
+
+//=============================================================================
+// Macros
+//=============================================================================
+
+#define UNREFERENCED_VAR(status) \
+ status = status
+
+//-------------------------------------------------------------------------
+// Description:
+//
+// jump to the given label.
+//
+// Parameters:
+//
+// label - [in] label to jump if condition is met
+//
+#define JUMP(label) \
+ goto label;
+
+//-------------------------------------------------------------------------
+// Description:
+//
+// If the condition evaluates to TRUE, jump to the given label.
+//
+// Parameters:
+//
+// condition - [in] Code that fits in if statement
+// label - [in] label to jump if condition is met
+//
+#define IF_TRUE_JUMP(condition, label) \
+ if (condition) \
+ { \
+ goto label; \
+ }
+
+//-------------------------------------------------------------------------
+// Description:
+//
+// If the condition evaluates to TRUE, perform the given statement
+// then jump to the given label.
+//
+// Parameters:
+//
+// condition - [in] Code that fits in if statement
+// action - [in] action to perform in body of if statement
+// label - [in] label to jump if condition is met
+//
+#define IF_TRUE_ACTION_JUMP(condition, action, label) \
+ if (condition) \
+ { \
+ action; \
+ goto label; \
+ }
+
+//-------------------------------------------------------------------------
+// Description:
+//
+// If the ntStatus is not NT_SUCCESS, perform the given statement then jump to
+// the given label.
+//
+// Parameters:
+//
+// ntStatus - [in] Value to check
+// action - [in] action to perform in body of if statement
+// label - [in] label to jump if condition is met
+//
+#define IF_FAILED_ACTION_JUMP(ntStatus, action, label) \
+ if (!NT_SUCCESS(ntStatus)) \
+ { \
+ action; \
+ goto label; \
+ }
+
+//-------------------------------------------------------------------------
+// Description:
+//
+// If the ntStatus passed is not NT_SUCCESS, jump to the given label.
+//
+// Parameters:
+//
+// ntStatus - [in] Value to check
+// label - [in] label to jump if condition is met
+//
+#define IF_FAILED_JUMP(ntStatus, label) \
+ if (!NT_SUCCESS(ntStatus)) \
+ { \
+ goto label; \
+ }
+
+#define SAFE_RELEASE(p) {if (p) { (p)->Release(); (p) = nullptr; } }
+#define SAFE_DELETE_PTR_WITH_TAG(ptr, tag) if(ptr) { ExFreePoolWithTag((ptr), tag); (ptr) = NULL; }
+
+// JACKDESC_RGB(r, g, b)
+#define JACKDESC_RGB(r, g, b) \
+ ((COLORREF)((r << 16) | (g << 8) | (b)))
+
+// Min/Max defines.
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+
+#define MINWAVERT_POOLTAG 'RWNM'
+#define MINTOPORT_POOLTAG 'RTNM'
+#define MINADAPTER_POOLTAG 'uAyS'
+
+typedef enum
+{
+ eSpeakerDevice = 0,
+ eMicArrayDevice1,
+ eMaxDeviceType,
+} eDeviceType;
+
+//
+// Signal processing modes and default formats structs.
+//
+typedef struct _MODE_AND_DEFAULT_FORMAT {
+ GUID Mode;
+ KSDATAFORMAT* DefaultFormat;
+} MODE_AND_DEFAULT_FORMAT, *PMODE_AND_DEFAULT_FORMAT;
+
+//
+// Enumeration of the various types of pins implemented in this driver.
+//
+typedef enum
+{
+ NoPin,
+ BridgePin,
+ SystemRenderPin,
+ SystemCapturePin,
+} PINTYPE;
+
+//
+// PIN_DEVICE_FORMATS_AND_MODES
+//
+// Used to specify a pin's type (e.g. system, offload, etc.), formats, and
+// modes. Conceptually serves similar purpose as the PCPIN_DESCRIPTOR to
+// define a pin, but is more specific to driver implementation.
+//
+// Arrays of these structures follow the same order as the filter's
+// pin descriptor array so that KS pin IDs can serve as an index.
+//
+typedef struct _PIN_DEVICE_FORMATS_AND_MODES
+{
+ PINTYPE PinType;
+
+ KSDATAFORMAT_WAVEFORMATEXTENSIBLE * WaveFormats;
+ ULONG WaveFormatsCount;
+
+ MODE_AND_DEFAULT_FORMAT * ModeAndDefaultFormat;
+ ULONG ModeAndDefaultFormatCount;
+
+} PIN_DEVICE_FORMATS_AND_MODES, *PPIN_DEVICE_FORMATS_AND_MODES;
+
+// forward declaration.
+typedef struct _ENDPOINT_MINIPAIR *PENDPOINT_MINIPAIR;
+
+// both wave & topology miniport create function prototypes have this form:
+typedef HRESULT (*PFNCREATEMINIPORT)(
+ _Out_ PUNKNOWN * Unknown,
+ _In_ REFCLSID,
+ _In_opt_ PUNKNOWN UnknownOuter,
+ _In_ POOL_FLAGS PoolFlags,
+ _In_ PUNKNOWN UnknownAdapter,
+ _In_opt_ PVOID DeviceContext,
+ _In_ PENDPOINT_MINIPAIR MiniportPair
+);
+
+//=============================================================================
+//
+//=============================================================================
+typedef struct _SIMPLEAUDIOSAMPLE_DEVPROPERTY {
+ const DEVPROPKEY *PropertyKey;
+ DEVPROPTYPE Type;
+ ULONG BufferSize;
+ __field_bcount_opt(BufferSize) PVOID Buffer;
+} SIMPLEAUDIOSAMPLE_DEVPROPERTY, PSIMPLEAUDIOSAMPLE_DEVPROPERTY;
+
+#define ENDPOINT_NO_FLAGS 0x00000000
+#define ENDPOINT_CELLULAR_PROVIDER1 0x00000008
+#define ENDPOINT_CELLULAR_PROVIDER2 0x00000010
+
+//
+// Endpoint miniport pair (wave/topology) descriptor.
+//
+typedef struct _ENDPOINT_MINIPAIR
+{
+ eDeviceType DeviceType;
+
+ // Topology miniport.
+ PWSTR TopoName; // make sure this or the template name matches with SIMPLEAUDIOSAMPLE.<TopoName>.szPname in the inf's [Strings] section
+ PWSTR TemplateTopoName; // optional template name
+ PFNCREATEMINIPORT TopoCreateCallback;
+ PCFILTER_DESCRIPTOR* TopoDescriptor;
+ ULONG TopoInterfacePropertyCount;
+ const SIMPLEAUDIOSAMPLE_DEVPROPERTY* TopoInterfaceProperties;
+
+ // Wave RT miniport.
+ PWSTR WaveName; // make sure this or the template name matches with SIMPLEAUDIOSAMPLE.<WaveName>.szPname in the inf's [Strings] section
+ PWSTR TemplateWaveName; // optional template name
+ PFNCREATEMINIPORT WaveCreateCallback;
+ PCFILTER_DESCRIPTOR* WaveDescriptor;
+ ULONG WaveInterfacePropertyCount;
+ const SIMPLEAUDIOSAMPLE_DEVPROPERTY* WaveInterfaceProperties;
+
+ USHORT DeviceMaxChannels;
+ PIN_DEVICE_FORMATS_AND_MODES* PinDeviceFormatsAndModes;
+ ULONG PinDeviceFormatsAndModesCount;
+
+ // Miniport physical connections.
+ PHYSICALCONNECTIONTABLE* PhysicalConnections;
+ ULONG PhysicalConnectionCount;
+
+ // General endpoint flags (one of more ENDPOINT_<flag-type>, see above)
+ ULONG DeviceFlags;
+} ENDPOINT_MINIPAIR;
+
+//=============================================================================
+// Defines
+//=============================================================================
+
+DEFINE_GUID(IID_IAdapterCommon,
+0x7eda2950, 0xbf9f, 0x11d0, 0x87, 0x1f, 0x0, 0xa0, 0xc9, 0x11, 0xb5, 0x44);
+
+//=============================================================================
+// Interfaces
+//=============================================================================
+
+///////////////////////////////////////////////////////////////////////////////
+// IAdapterCommon
+//
+DECLARE_INTERFACE_(IAdapterCommon, IUnknown)
+{
+ STDMETHOD_(NTSTATUS, Init)
+ (
+ THIS_
+ _In_ PDEVICE_OBJECT DeviceObject
+ ) PURE;
+
+ STDMETHOD_(PDEVICE_OBJECT, GetDeviceObject)
+ (
+ THIS
+ ) PURE;
+
+ STDMETHOD_(PDEVICE_OBJECT, GetPhysicalDeviceObject)
+ (
+ THIS
+ ) PURE;
+
+ STDMETHOD_(WDFDEVICE, GetWdfDevice)
+ (
+ THIS
+ ) PURE;
+
+ STDMETHOD_(VOID, SetWaveServiceGroup)
+ (
+ THIS_
+ _In_ PSERVICEGROUP ServiceGroup
+ ) PURE;
+
+ STDMETHOD_(BOOL, bDevSpecificRead)
+ (
+ THIS_
+ ) PURE;
+
+ STDMETHOD_(VOID, bDevSpecificWrite)
+ (
+ THIS_
+ _In_ BOOL bDevSpecific
+ );
+
+ STDMETHOD_(INT, iDevSpecificRead)
+ (
+ THIS_
+ ) PURE;
+
+ STDMETHOD_(VOID, iDevSpecificWrite)
+ (
+ THIS_
+ _In_ INT iDevSpecific
+ );
+
+ STDMETHOD_(UINT, uiDevSpecificRead)
+ (
+ THIS_
+ ) PURE;
+
+ STDMETHOD_(VOID, uiDevSpecificWrite)
+ (
+ THIS_
+ _In_ UINT uiDevSpecific
+ );
+
+ STDMETHOD_(BOOL, MixerMuteRead)
+ (
+ THIS_
+ _In_ ULONG Index,
+ _In_ ULONG Channel
+ ) PURE;
+
+ STDMETHOD_(VOID, MixerMuteWrite)
+ (
+ THIS_
+ _In_ ULONG Index,
+ _In_ ULONG Channel,
+ _In_ BOOL Value
+ );
+
+ STDMETHOD_(ULONG, MixerMuxRead)
+ (
+ THIS
+ );
+
+ STDMETHOD_(VOID, MixerMuxWrite)
+ (
+ THIS_
+ _In_ ULONG Index
+ );
+
+ STDMETHOD_(LONG, MixerVolumeRead)
+ (
+ THIS_
+ _In_ ULONG Index,
+ _In_ ULONG Channel
+ ) PURE;
+
+ STDMETHOD_(VOID, MixerVolumeWrite)
+ (
+ THIS_
+ _In_ ULONG Index,
+ _In_ ULONG Channel,
+ _In_ LONG Value
+ ) PURE;
+
+ STDMETHOD_(LONG, MixerPeakMeterRead)
+ (
+ THIS_
+ _In_ ULONG Index,
+ _In_ ULONG Channel
+ ) PURE;
+
+ STDMETHOD_(VOID, MixerReset)
+ (
+ THIS
+ ) PURE;
+
+ STDMETHOD_(NTSTATUS, WriteEtwEvent)
+ (
+ THIS_
+ _In_ EPcMiniportEngineEvent miniportEventType,
+ _In_ ULONGLONG ullData1,
+ _In_ ULONGLONG ullData2,
+ _In_ ULONGLONG ullData3,
+ _In_ ULONGLONG ullData4
+ ) PURE;
+
+ STDMETHOD_(VOID, SetEtwHelper)
+ (
+ THIS_
+ PPORTCLSETWHELPER _pPortClsEtwHelper
+ ) PURE;
+
+ STDMETHOD_(NTSTATUS, InstallSubdevice)
+ (
+ _In_opt_ PIRP Irp,
+ _In_ PWSTR Name,
+ _In_opt_ PWSTR TemplateName,
+ _In_ REFGUID PortClassId,
+ _In_ REFGUID MiniportClassId,
+ _In_opt_ PFNCREATEMINIPORT MiniportCreate,
+ _In_ ULONG cPropertyCount,
+ _In_reads_opt_(cPropertyCount) const SIMPLEAUDIOSAMPLE_DEVPROPERTY * pProperties,
+ _In_opt_ PVOID DeviceContext,
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_opt_ PRESOURCELIST ResourceList,
+ _In_ REFGUID PortInterfaceId,
+ _Out_opt_ PUNKNOWN * OutPortInterface,
+ _Out_opt_ PUNKNOWN * OutPortUnknown,
+ _Out_opt_ PUNKNOWN * OutMiniportUnknown
+ );
+
+ STDMETHOD_(NTSTATUS, UnregisterSubdevice)
+ (
+ THIS_
+ _In_opt_ PUNKNOWN UnknownPort
+ );
+
+ STDMETHOD_(NTSTATUS, ConnectTopologies)
+ (
+ THIS_
+ _In_ PUNKNOWN UnknownTopology,
+ _In_ PUNKNOWN UnknownWave,
+ _In_ PHYSICALCONNECTIONTABLE* PhysicalConnections,
+ _In_ ULONG PhysicalConnectionCount
+ );
+
+ STDMETHOD_(NTSTATUS, DisconnectTopologies)
+ (
+ THIS_
+ _In_ PUNKNOWN UnknownTopology,
+ _In_ PUNKNOWN UnknownWave,
+ _In_ PHYSICALCONNECTIONTABLE* PhysicalConnections,
+ _In_ ULONG PhysicalConnectionCount
+ );
+
+ STDMETHOD_(NTSTATUS, InstallEndpointFilters)
+ (
+ THIS_
+ _In_opt_ PIRP Irp,
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_opt_ PVOID DeviceContext,
+ _Out_opt_ PUNKNOWN * UnknownTopology,
+ _Out_opt_ PUNKNOWN * UnknownWave,
+ _Out_opt_ PUNKNOWN * UnknownMiniportTopology,
+ _Out_opt_ PUNKNOWN * UnknownMiniportWave
+ );
+
+ STDMETHOD_(NTSTATUS, RemoveEndpointFilters)
+ (
+ THIS_
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_opt_ PUNKNOWN UnknownTopology,
+ _In_opt_ PUNKNOWN UnknownWave
+ );
+
+ STDMETHOD_(NTSTATUS, GetFilters)
+ (
+ THIS_
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _Out_opt_ PUNKNOWN *UnknownTopologyPort,
+ _Out_opt_ PUNKNOWN *UnknownTopologyMiniport,
+ _Out_opt_ PUNKNOWN *UnknownWavePort,
+ _Out_opt_ PUNKNOWN *UnknownWaveMiniport
+ );
+
+ STDMETHOD_(NTSTATUS, SetIdlePowerManagement)
+ (
+ THIS_
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_ BOOL bEnable
+ );
+
+ STDMETHOD_(VOID, Cleanup)();
+
+};
+
+typedef IAdapterCommon *PADAPTERCOMMON;
+
+//=============================================================================
+// Function Prototypes
+//=============================================================================
+NTSTATUS
+NewAdapterCommon
+(
+ _Out_ PUNKNOWN * Unknown,
+ _In_ REFCLSID,
+ _In_opt_ PUNKNOWN UnknownOuter,
+ _In_ POOL_FLAGS PoolFlags
+);
+
+#endif //_SIMPLEAUDIOSAMPLE_COMMON_H_
diff --git a/audio/simpleaudiosample/Source/Inc/definitions.h b/audio/simpleaudiosample/Source/Inc/definitions.h
new file mode 100644
index 00000000..9fb4547a
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Inc/definitions.h
@@ -0,0 +1,198 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ Definitions.h
+
+Abstract:
+
+ Header file for common stuff.
+--*/
+
+#ifndef _SIMPLEAUDIOSAMPLE_DEFINITIONS_H_
+#define _SIMPLEAUDIOSAMPLE_DEFINITIONS_H_
+
+#include <portcls.h>
+#include <stdunk.h>
+#include <ksdebug.h>
+#include <ntintsafe.h>
+#include <wdf.h>
+#include <wdfminiport.h>
+#include <Ntstrsafe.h>
+#include "NewDelete.h"
+
+//=============================================================================
+// Defines
+//=============================================================================
+
+// Product Id
+// {836BA6D1-3FF7-4411-8BCD-469553452DCE}
+#define STATIC_PID_SIMPLEAUDIOSAMPLE\
+ 0x836ba6d1, 0x3ff7, 0x4411, 0x8b, 0xcd, 0x46, 0x95, 0x53, 0x45, 0x2d, 0xce
+DEFINE_GUIDSTRUCT("836BA6D1-3FF7-4411-8BCD-469553452DCE", PID_SIMPLEAUDIOSAMPLE);
+#define PID_SIMPLEAUDIOSAMPLE DEFINE_GUIDNAMED(PID_SIMPLEAUDIOSAMPLE)
+
+// Pool tag used for SIMPLEAUDIOSAMPLE allocations
+#define SIMPLEAUDIOSAMPLE_POOLTAG 'SASM'
+
+// Debug module name
+#define STR_MODULENAME "SIMPLEAUDIOSAMPLE: "
+
+// Debug utility macros
+#define D_FUNC 4
+#define D_BLAB DEBUGLVL_BLAB
+#define D_VERBOSE DEBUGLVL_VERBOSE
+#define D_TERSE DEBUGLVL_TERSE
+#define D_ERROR DEBUGLVL_ERROR
+#define DPF _DbgPrintF
+#define DPF_ENTER(x) DPF(D_FUNC, x)
+
+// Channel orientation
+#define CHAN_LEFT 0
+#define CHAN_RIGHT 1
+#define CHAN_MASTER (-1)
+
+// Dma Settings.
+#define DMA_BUFFER_SIZE 0x16000
+
+#define KSPROPERTY_TYPE_ALL KSPROPERTY_TYPE_BASICSUPPORT | \
+ KSPROPERTY_TYPE_GET | \
+ KSPROPERTY_TYPE_SET
+
+// Specific node numbers
+#define DEV_SPECIFIC_VT_BOOL 9
+#define DEV_SPECIFIC_VT_I4 10
+#define DEV_SPECIFIC_VT_UI4 11
+
+#define _100NS_PER_MILLISECOND 10000 // number of 100ns units per millisecond
+
+// Default volume settings.
+#define VOLUME_STEPPING_DELTA 0x8000
+#define VOLUME_SIGNED_MAXIMUM 0x00000000
+#define VOLUME_SIGNED_MINIMUM (-96 * 0x10000)
+
+// Default peak meter settings
+#define PEAKMETER_STEPPING_DELTA 0x1000
+#define PEAKMETER_SIGNED_MAXIMUM LONG_MAX
+#define PEAKMETER_SIGNED_MINIMUM LONG_MIN
+
+#define VALUE_NORMALIZE_P(v, step) \
+ ((((v) + (step)/2) / (step)) * (step))
+
+#define VALUE_NORMALIZE(v, step) \
+ ((v) > 0 ? VALUE_NORMALIZE_P((v), (step)) : -(VALUE_NORMALIZE_P(-(v), (step))))
+
+#define VALUE_NORMALIZE_IN_RANGE_EX(v, min, max, step) \
+ ((v) > (max) ? (max) : \
+ (v) < (min) ? (min) : \
+ VALUE_NORMALIZE((v), (step)))
+
+// to normalize volume values.
+#define VOLUME_NORMALIZE_IN_RANGE(v) \
+ VALUE_NORMALIZE_IN_RANGE_EX((v), VOLUME_SIGNED_MINIMUM, VOLUME_SIGNED_MAXIMUM, VOLUME_STEPPING_DELTA)
+
+// to normalize sample peak meter.
+#define PEAKMETER_NORMALIZE_IN_RANGE(v) \
+ VALUE_NORMALIZE_IN_RANGE_EX((v), PEAKMETER_SIGNED_MINIMUM, PEAKMETER_SIGNED_MAXIMUM, PEAKMETER_STEPPING_DELTA)
+
+#define ALL_CHANNELS_ID UINT32_MAX
+
+// Macros to assist with pin instance counting
+#define VERIFY_PIN_INSTANCE_RESOURCES_AVAILABLE(status, allocated, max) \
+ status = (allocated < max) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES
+
+#define ALLOCATE_PIN_INSTANCE_RESOURCES(allocated) \
+ allocated++
+
+#define FREE_PIN_INSTANCE_RESOURCES(allocated) \
+ allocated--
+
+// Define the value data type for supported sound detector patterns. Only
+// one pattern type is supported in this sample.
+typedef struct {
+ KSMULTIPLE_ITEM MultipleItem;
+ GUID PatternType[1];
+} CONTOSO_SUPPORTEDPATTERNSVALUE;
+
+//=============================================================================
+// Typedefs
+//=============================================================================
+
+// Flags to identify stream processing mode
+typedef enum {
+ CONNECTIONTYPE_TOPOLOGY_OUTPUT = 0,
+ CONNECTIONTYPE_WAVE_OUTPUT = 1
+} CONNECTIONTYPE;
+
+// Connection table for registering topology/wave bridge connection
+typedef struct _PHYSICALCONNECTIONTABLE
+{
+ ULONG ulTopology;
+ ULONG ulWave;
+ CONNECTIONTYPE eType;
+} PHYSICALCONNECTIONTABLE, *PPHYSICALCONNECTIONTABLE;
+
+//
+// This is the structure of the portclass FDO device extension Nt has created
+// for us. We keep the adapter common object here.
+//
+struct IAdapterCommon;
+typedef struct _PortClassDeviceContext // 32 64 Byte offsets for 32 and 64 bit architectures
+{
+ ULONG_PTR m_pulReserved1[2]; // 0-7 0-15 First two pointers are reserved.
+ PDEVICE_OBJECT m_DoNotUsePhysicalDeviceObject; // 8-11 16-23 Reserved pointer to our Physical Device Object (PDO).
+ PVOID m_pvReserved2; // 12-15 24-31 Reserved pointer to our Start Device function.
+ PVOID m_pvReserved3; // 16-19 32-39 "Out Memory" according to DDK.
+ IAdapterCommon* m_pCommon; // 20-23 40-47 Pointer to our adapter common object.
+ PVOID m_pvUnused1; // 24-27 48-55 Unused space.
+ PVOID m_pvUnused2; // 28-31 56-63 Unused space.
+
+ // Anything after above line should not be used.
+ // This actually goes on for (64*sizeof(ULONG_PTR)) but it is all opaque.
+} PortClassDeviceContext;
+
+//
+// Major/MinorTarget to object casting.
+//
+#define MajorTarget_to_Obj(ptr) \
+ reinterpret_cast<CMiniportWaveRT*>(ptr)
+
+#define MinorTarget_to_Obj(ptr) \
+ static_cast<CMiniportWaveRTStream*>(reinterpret_cast<PMINIPORTWAVERTSTREAM>(ptr))
+
+//
+// Global settings.
+//
+extern DWORD g_DoNotCreateDataFiles;
+extern DWORD g_DisableBthScoBypass;
+extern UNICODE_STRING g_RegistryPath;
+
+//=============================================================================
+// Function prototypes
+//=============================================================================
+
+// Generic topology handler
+NTSTATUS PropertyHandler_Topology
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+);
+
+// Default WaveFilter automation table.
+// Handles the GeneralComponentId request.
+NTSTATUS PropertyHandler_WaveFilter
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+);
+
+NTSTATUS PropertyHandler_GenericPin
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+);
+
+// common.h uses some of the above definitions.
+#include "common.h"
+#include "kshelper.h"
+
+#endif // _SIMPLEAUDIOSAMPLE_DEFINITIONS_H_
diff --git a/audio/simpleaudiosample/Source/Inc/endpoints.h b/audio/simpleaudiosample/Source/Inc/endpoints.h
new file mode 100644
index 00000000..44a858a0
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Inc/endpoints.h
@@ -0,0 +1,133 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ endpoints.h
+
+Abstract:
+
+ Node and Pin numbers and other common definitions for simple audio sample.
+--*/
+
+#ifndef _SIMPLEAUDIOSAMPLE_ENDPOINTS_H_
+#define _SIMPLEAUDIOSAMPLE_ENDPOINTS_H_
+
+// Name Guid
+// {0104947F-82AE-4291-A6F3-5E2DE1AD7DC2}
+#define STATIC_NAME_SIMPLE_AUDIO_SAMPLE\
+ 0x104947f, 0x82ae, 0x4291, 0xa6, 0xf3, 0x5e, 0x2d, 0xe1, 0xad, 0x7d, 0xc2
+DEFINE_GUIDSTRUCT("0104947F-82AE-4291-A6F3-5E2DE1AD7DC2", NAME_SIMPLE_AUDIO_SAMPLE);
+#define NAME_SIMPLE_AUDIO_SAMPLE DEFINE_GUIDNAMED(NAME_SIMPLE_AUDIO_SAMPLE)
+
+//----------------------------------------------------
+// New defines for the render endpoints.
+//----------------------------------------------------
+
+// Default pin instances.
+#define MAX_INPUT_SYSTEM_STREAMS 1
+
+// Wave pins - no mix, no offload
+enum
+{
+ KSPIN_WAVE_RENDER3_SINK_SYSTEM = 0,
+ KSPIN_WAVE_RENDER3_SOURCE
+};
+
+// Wave pins - offloading is NOT supported.
+enum
+{
+ KSPIN_WAVE_RENDER2_SINK_SYSTEM = 0,
+ KSPIN_WAVE_RENDER2_SINK_LOOPBACK,
+ KSPIN_WAVE_RENDER2_SOURCE
+};
+
+// Wave Topology nodes - offloading is NOT supported.
+enum
+{
+ KSNODE_WAVE_SUM = 0,
+ KSNODE_WAVE_VOLUME,
+ KSNODE_WAVE_MUTE,
+ KSNODE_WAVE_PEAKMETER
+};
+
+// Topology pins.
+enum
+{
+ KSPIN_TOPO_WAVEOUT_SOURCE = 0,
+ KSPIN_TOPO_LINEOUT_DEST,
+};
+
+// Topology nodes.
+enum
+{
+ KSNODE_TOPO_WAVEOUT_VOLUME = 0,
+ KSNODE_TOPO_WAVEOUT_MUTE,
+ KSNODE_TOPO_WAVEOUT_PEAKMETER
+};
+
+//----------------------------------------------------
+// New defines for the capture endpoints.
+//----------------------------------------------------
+
+// Default pin instances.
+#define MAX_INPUT_STREAMS 1 // Number of capture streams.
+
+// Wave pins
+enum
+{
+ KSPIN_WAVE_BRIDGE = 0,
+ KSPIN_WAVEIN_HOST,
+};
+
+// Wave Topology nodes.
+enum
+{
+ KSNODE_WAVE_ADC = 0
+};
+
+// Wave Topology nodes.
+enum
+{
+ KSNODE_WAVE_DAC = 0
+};
+
+// topology pins.
+enum
+{
+ KSPIN_TOPO_MIC_ELEMENTS,
+ KSPIN_TOPO_BRIDGE
+};
+
+// topology nodes.
+enum
+{
+ KSNODE_TOPO_VOLUME,
+ KSNODE_TOPO_MUTE,
+ KSNODE_TOPO_PEAKMETER
+};
+
+// data format attribute range definitions.
+static
+KSATTRIBUTE PinDataRangeSignalProcessingModeAttribute =
+{
+ sizeof(KSATTRIBUTE),
+ 0,
+ STATICGUIDOF(KSATTRIBUTEID_AUDIOSIGNALPROCESSING_MODE),
+};
+
+static
+PKSATTRIBUTE PinDataRangeAttributes[] =
+{
+ &PinDataRangeSignalProcessingModeAttribute,
+};
+
+static
+KSATTRIBUTE_LIST PinDataRangeAttributeList =
+{
+ ARRAYSIZE(PinDataRangeAttributes),
+ PinDataRangeAttributes,
+};
+
+#endif // _SIMPLEAUDIOSAMPLE_ENDPOINTS_H_
diff --git a/audio/simpleaudiosample/Source/Inc/kshelper.h b/audio/simpleaudiosample/Source/Inc/kshelper.h
new file mode 100644
index 00000000..023f773a
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Inc/kshelper.h
@@ -0,0 +1,159 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ kshelper.h
+
+Abstract:
+
+ Helper functions for simple audio sample
+--*/
+#ifndef _SIMPLEAUDIOSAMPLE_KSHELPER_H_
+#define _SIMPLEAUDIOSAMPLE_KSHELPER_H_
+
+#include <portcls.h>
+#include <ksdebug.h>
+
+PWAVEFORMATEX
+GetWaveFormatEx
+(
+ _In_ PKSDATAFORMAT pDataFormat
+);
+
+NTSTATUS
+ValidatePropertyParams
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG cbValueSize,
+ _In_ ULONG cbInstanceSize = 0
+);
+
+NTSTATUS
+PropertyHandler_BasicSupport
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG Flags,
+ _In_ DWORD PropTypeSetId
+);
+
+NTSTATUS
+PropertyHandler_BasicSupportVolume
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG MaxChannels
+);
+
+NTSTATUS
+PropertyHandler_BasicSupportMute
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG MaxChannels
+);
+
+NTSTATUS
+PropertyHandler_BasicSupportPeakMeter2
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG MaxChannels
+);
+
+NTSTATUS
+PropertyHandler_CpuResources
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+);
+
+NTSTATUS
+PropertyHandler_Volume
+(
+ _In_ PADAPTERCOMMON AdapterCommon,
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG MaxChannels
+);
+
+NTSTATUS
+PropertyHandler_Mute
+(
+ _In_ PADAPTERCOMMON AdapterCommon,
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG MaxChannels
+);
+
+NTSTATUS
+PropertyHandler_PeakMeter2
+(
+ _In_ PADAPTERCOMMON AdapterCommon,
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG MaxChannels
+);
+
+//=============================================================================
+// Property helpers
+//=============================================================================
+
+NTSTATUS
+SimpleAudioSamplePropertyDispatch
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+);
+
+// Use this structure to define property items with extra data allowing easier
+// definition of separate get, set, and support handlers dispatched through
+// SimpleAudioSamplePropertyDispatch.
+typedef struct
+{
+ PCPROPERTY_ITEM PropertyItem; // Standard PCPROPERTY_ITEM
+ ULONG MinProperty; // Minimum size of the property instance data
+ ULONG MinData; // Minimum size of the property value
+ PCPFNPROPERTY_HANDLER GetHandler; // Property get handler (NULL if GET not supported)
+ PCPFNPROPERTY_HANDLER SetHandler; // Property set handler (NULL if SET not supported)
+ PCPFNPROPERTY_HANDLER SupportHandler; // Property support handler (NULL for common handler)
+ VOID *ContextData; // Optional context information for the handler, NULL for unused
+ ULONG ContextDataSize; // Size of the data held at ContextData, 0 for unused
+} SIMPLEAUDIOSAMPLE_PROPERTY_ITEM;
+
+// The following macros facilitate adding property handlers to a class, allowing
+// easier declaration and definition of a "thunk" routine that directly handles
+// the property request and calls into a class instance method. Note that as
+// written, the thunk routine assumes PAGED_CODE.
+#define DECLARE_CLASSPROPERTYHANDLER(theClass, theMethod) \
+NTSTATUS theClass##_##theMethod \
+( \
+ _In_ PPCPROPERTY_REQUEST PropertyRequest \
+);
+
+#define DECLARE_PROPERTYHANDLER(theMethod) \
+NTSTATUS theMethod \
+( \
+ _In_ PPCPROPERTY_REQUEST PropertyRequest \
+);
+
+#define DEFINE_CLASSPROPERTYHANDLER(theClass, theMethod) \
+NTSTATUS theClass##_##theMethod \
+( \
+ _In_ PPCPROPERTY_REQUEST PropertyRequest \
+) \
+{ \
+ NTSTATUS status; \
+ \
+ PAGED_CODE(); \
+ \
+ theClass* p = reinterpret_cast<theClass*>(PropertyRequest->MajorTarget); \
+ \
+ p->AddRef(); \
+ status = p->theMethod(PropertyRequest); \
+ p->Release(); \
+ \
+ return status; \
+} \
+NTSTATUS theClass::theMethod \
+( \
+ _In_ PPCPROPERTY_REQUEST PropertyRequest \
+)
+
+
+
+
+#endif // _SIMPLEAUDIOSAMPLE_KSHELPER_H_
diff --git a/audio/simpleaudiosample/Source/Inc/mintopo.h b/audio/simpleaudiosample/Source/Inc/mintopo.h
new file mode 100644
index 00000000..5e7fe466
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Inc/mintopo.h
@@ -0,0 +1,81 @@
+
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ minitopo.h
+
+Abstract:
+
+ Declaration of topology miniport.
+--*/
+
+#ifndef _SIMPLEAUDIOSAMPLE_MINTOPO_H_
+#define _SIMPLEAUDIOSAMPLE_MINTOPO_H_
+
+#include "basetopo.h"
+
+//=============================================================================
+// Classes
+//=============================================================================
+
+///////////////////////////////////////////////////////////////////////////////
+// CMiniportTopology
+//
+
+class CMiniportTopology :
+ public CMiniportTopologySimpleAudioSample,
+ public IMiniportTopology,
+ public CUnknown
+{
+ private:
+ eDeviceType m_DeviceType;
+
+ union {
+ PVOID m_DeviceContext;
+ };
+
+public:
+ DECLARE_STD_UNKNOWN();
+ CMiniportTopology
+ (
+ _In_opt_ PUNKNOWN UnknownOuter,
+ _In_ PCFILTER_DESCRIPTOR *FilterDesc,
+ _In_ USHORT DeviceMaxChannels,
+ _In_ eDeviceType DeviceType,
+ _In_opt_ PVOID DeviceContext
+ )
+ : CUnknown(UnknownOuter),
+ CMiniportTopologySimpleAudioSample(FilterDesc, DeviceMaxChannels),
+ m_DeviceType(DeviceType),
+ m_DeviceContext(DeviceContext)
+ {
+ }
+
+ ~CMiniportTopology();
+
+ IMP_IMiniportTopology;
+
+ NTSTATUS PropertyHandlerJackDescription
+ (
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG cJackDescriptions,
+ _In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION *JackDescriptions
+ );
+
+ NTSTATUS PropertyHandlerJackDescription2
+ (
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG cJackDescriptions,
+ _In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION *JackDescriptions,
+ _In_ DWORD JackCapabilities
+ );
+
+ PVOID GetDeviceContext() { return m_DeviceContext; }
+};
+
+typedef CMiniportTopology *PCMiniportTopology;
+
+#endif // _SIMPLEAUDIOSAMPLE_MINTOPO_H_
diff --git a/audio/sysvad/PhoneAudioSample/PhoneAudioSample.vcxproj b/audio/simpleaudiosample/Source/Main/Main.vcxproj
index 49ccee70..a68d0242 100644
--- a/audio/sysvad/PhoneAudioSample/PhoneAudioSample.vcxproj
+++ b/audio/simpleaudiosample/Source/Main/Main.vcxproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM64">
@@ -27,14 +27,14 @@
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
- <ProjectGuid>{FABA4668-DB5E-4F6C-9D25-A0B25AD084EE}</ProjectGuid>
+ <ProjectGuid>{E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}</ProjectGuid>
<RootNamespace>$(MSBuildProjectName)</RootNamespace>
<KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
<SupportsPackaging>false</SupportsPackaging>
<RequiresPackageProject>true</RequiresPackageProject>
<Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
- <SampleGuid>{791E3C3E-132D-46C6-9624-C868C54139F0}</SampleGuid>
+ <SampleGuid>{2A9A946E-F017-4E0D-BF75-AD81E7E97D64}</SampleGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -129,6 +129,9 @@
<PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
</Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<Link>
@@ -151,6 +154,9 @@
<PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
</Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Link>
@@ -173,6 +179,9 @@
<PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
</Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<Link>
@@ -195,6 +204,9 @@
<PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
</Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Link>
@@ -217,6 +229,9 @@
<PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
</Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Link>
@@ -239,31 +254,37 @@
<PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
</Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <TargetName>PhoneAudioSample</TargetName>
+ <TargetName>SimpleAudioSample</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
- <TargetName>PhoneAudioSample</TargetName>
+ <TargetName>SimpleAudioSample</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <TargetName>PhoneAudioSample</TargetName>
+ <TargetName>SimpleAudioSample</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
- <TargetName>PhoneAudioSample</TargetName>
+ <TargetName>SimpleAudioSample</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <TargetName>PhoneAudioSample</TargetName>
+ <TargetName>SimpleAudioSample</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <TargetName>PhoneAudioSample</TargetName>
+ <TargetName>SimpleAudioSample</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Link>
- <AdditionalDependencies>%(AdditionalDependencies);.\..\EndpointsCommon\$(IntDir)\EndpointsCommon.lib</AdditionalDependencies>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Utilities\$(IntDir)\Utilities.lib</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Filters\$(IntDir)\Filters.lib</AdditionalDependencies>
</Link>
<ClCompile>
- <!--
+ <!--
Use one of the following pre-processor defines to select the right power management:
- _USE_IPortClsRuntimePower
- _USE_SingleComponentMultiFxStates
@@ -271,137 +292,175 @@
value set via the INF. The name of the registry value is SingleComponentMultiFxStates.
see INF file for more info.
-->
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
<ExceptionHandling>
</ExceptionHandling>
</ClCompile>
<Midl>
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
</Midl>
<ResourceCompile>
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<Link>
- <AdditionalDependencies>%(AdditionalDependencies);.\..\EndpointsCommon\$(IntDir)\EndpointsCommon.lib</AdditionalDependencies>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Utilities\$(IntDir)\Utilities.lib</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Filters\$(IntDir)\Filters.lib</AdditionalDependencies>
</Link>
<ClCompile>
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
<ExceptionHandling>
</ExceptionHandling>
- <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Midl>
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
</Midl>
<ResourceCompile>
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Link>
- <AdditionalDependencies>%(AdditionalDependencies);.\..\EndpointsCommon\$(IntDir)\EndpointsCommon.lib</AdditionalDependencies>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Utilities\$(IntDir)\Utilities.lib</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Filters\$(IntDir)\Filters.lib</AdditionalDependencies>
</Link>
<ClCompile>
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
<ExceptionHandling>
</ExceptionHandling>
</ClCompile>
<Midl>
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
</Midl>
<ResourceCompile>
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<Link>
- <AdditionalDependencies>%(AdditionalDependencies);.\..\EndpointsCommon\$(IntDir)\EndpointsCommon.lib</AdditionalDependencies>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Utilities\$(IntDir)\Utilities.lib</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Filters\$(IntDir)\Filters.lib</AdditionalDependencies>
</Link>
<ClCompile>
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
<ExceptionHandling>
</ExceptionHandling>
- <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Midl>
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
</Midl>
<ResourceCompile>
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Link>
- <AdditionalDependencies>%(AdditionalDependencies);.\..\EndpointsCommon\$(IntDir)\EndpointsCommon.lib</AdditionalDependencies>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Utilities\$(IntDir)\Utilities.lib</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Filters\$(IntDir)\Filters.lib</AdditionalDependencies>
</Link>
<ClCompile>
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
<ExceptionHandling>
</ExceptionHandling>
</ClCompile>
<Midl>
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
</Midl>
<ResourceCompile>
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Link>
- <AdditionalDependencies>%(AdditionalDependencies);.\..\EndpointsCommon\$(IntDir)\EndpointsCommon.lib</AdditionalDependencies>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Utilities\$(IntDir)\Utilities.lib</AdditionalDependencies>
+ </Link>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);.\..\Filters\$(IntDir)\Filters.lib</AdditionalDependencies>
</Link>
<ClCompile>
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
<ExceptionHandling>
</ExceptionHandling>
- <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Midl>
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
</Midl>
<ResourceCompile>
- <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
- <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemGroup>
- <ClCompile Include="..\adapter.cpp" />
- <ClCompile Include="..\basetopo.cpp" />
- <ClCompile Include="..\BthhfpDevice.cpp" />
- <ClCompile Include="..\usbhsdevice.cpp" />
- <ClCompile Include="..\common.cpp" />
- <ClCompile Include="..\hw.cpp" />
- <ClCompile Include="..\kshelper.cpp" />
- <ClCompile Include="..\savedata.cpp" />
- <ClCompile Include="..\tonegenerator.cpp" />
- <ClCompile Include="cellulartopo.cpp" />
- <ClCompile Include="cellularwave.cpp" />
- <ClCompile Include="fmtopo.cpp" />
- <ClCompile Include="fmwave.cpp" />
- <ClCompile Include="handsetmictopo.cpp" />
- <ClCompile Include="handsetspeakertopo.cpp" />
- <ClCompile Include="michstopo.cpp" />
- <ClCompile Include="speakerhstopo.cpp" />
- <ResourceCompile Include="PhoneAudioSample.rc" />
+ <ClCompile Include="adapter.cpp" />
+ <ClCompile Include="basetopo.cpp" />
+ <ClCompile Include="common.cpp" />
+ <ClCompile Include="mintopo.cpp" />
+ <ClCompile Include="minwavert.cpp" />
+ <ClCompile Include="minwavertstream.cpp" />
+ <ClCompile Include="newdelete.cpp" />
+ <ResourceCompile Include="SimpleAudioSample.rc" />
</ItemGroup>
<ItemGroup>
<Inf Exclude="@(Inx)" Include="*.inx" />
diff --git a/audio/simpleaudiosample/Source/Main/Main.vcxproj.Filters b/audio/simpleaudiosample/Source/Main/Main.vcxproj.Filters
new file mode 100644
index 00000000..0669f019
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/Main.vcxproj.Filters
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{7FE326AE-6214-4FE0-A27B-F229A098BDBC}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{64C16D2B-849C-4264-A615-18A8E8AC9505}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{46FAF4E8-F18C-4797-9CFA-2F3473BCB316}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{EE8F0A00-C1F0-4CB4-80E3-5FCC378E0BF4}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\*.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="*.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="SimpleAudioSample.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Include="*.inx">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+</Project>
diff --git a/audio/simpleaudiosample/Source/Main/NewDelete.cpp b/audio/simpleaudiosample/Source/Main/NewDelete.cpp
new file mode 100644
index 00000000..8ef3797d
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/NewDelete.cpp
@@ -0,0 +1,141 @@
+/*****************************************************************************
+* NewDelete.cpp - CPP placement new and delete operators implementation
+*****************************************************************************
+* Copyright (c) Microsoft Corporation All Rights Reserved
+*
+* Module Name:
+*
+* NewDelete.cpp
+*
+* Abstract:
+*
+* Definition of placement new and delete operators.
+*
+*/
+
+#ifdef _NEW_DELETE_OPERATORS_
+#ifdef __cplusplus
+extern "C" {
+#include <wdm.h>
+}
+#else
+#include <wdm.h>
+#endif
+
+#include "newDelete.h"
+#include "definitions.h"
+
+#pragma code_seg()
+/*****************************************************************************
+* Functions
+*/
+
+/*****************************************************************************
+* ::new()
+*****************************************************************************
+* New function for creating objects with a specified allocation tag.
+*/
+PVOID operator new
+(
+ size_t iSize,
+ POOL_FLAGS poolFlags,
+ ULONG tag
+)
+{
+ PVOID result = ExAllocatePool2(poolFlags, iSize, tag);
+
+ return result;
+}
+
+
+/*****************************************************************************
+* ::new()
+*****************************************************************************
+* New function for creating objects with a specified allocation tag.
+*/
+PVOID operator new
+(
+ size_t iSize,
+ POOL_FLAGS poolFlags
+)
+{
+ PVOID result = ExAllocatePool2(poolFlags, iSize, SIMPLEAUDIOSAMPLE_POOLTAG);
+
+ return result;
+}
+
+
+/*****************************************************************************
+* ::delete()
+*****************************************************************************
+* Delete with tag function.
+*/
+void __cdecl operator delete
+(
+ PVOID pVoid,
+ ULONG tag
+)
+{
+ if (pVoid)
+ {
+ ExFreePoolWithTag(pVoid, tag);
+ }
+}
+
+
+/*****************************************************************************
+* ::delete()
+*****************************************************************************
+* Sized Delete function.
+*/
+void __cdecl operator delete
+(
+ _Pre_maybenull_ __drv_freesMem(Mem) PVOID pVoid,
+ _In_ size_t cbSize
+)
+{
+ UNREFERENCED_PARAMETER(cbSize);
+
+ if (pVoid)
+ {
+ ExFreePoolWithTag(pVoid, SIMPLEAUDIOSAMPLE_POOLTAG);
+ }
+}
+
+
+/*****************************************************************************
+* ::delete()
+*****************************************************************************
+* Sized Array Delete function.
+*/
+void __cdecl operator delete[]
+(
+ _Pre_maybenull_ __drv_freesMem(Mem) PVOID pVoid,
+ _In_ size_t cbSize
+)
+{
+ UNREFERENCED_PARAMETER(cbSize);
+
+ if (pVoid)
+ {
+ ExFreePoolWithTag(pVoid, SIMPLEAUDIOSAMPLE_POOLTAG);
+ }
+}
+
+
+/*****************************************************************************
+* ::delete()
+*****************************************************************************
+* Array Delete function.
+*/
+void __cdecl operator delete[]
+(
+ _Pre_maybenull_ __drv_freesMem(Mem) PVOID pVoid
+)
+{
+ if (pVoid)
+ {
+ ExFreePoolWithTag(pVoid, SIMPLEAUDIOSAMPLE_POOLTAG);
+ }
+}
+#endif//_NEW_DELETE_OPERATORS_
diff --git a/audio/simpleaudiosample/Source/Main/SimpleAudioSample.inx b/audio/simpleaudiosample/Source/Main/SimpleAudioSample.inx
new file mode 100644
index 00000000..a63bb0ba
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/SimpleAudioSample.inx
Binary files differ
diff --git a/audio/sysvad/PhoneAudioSample/PhoneAudioSample.rc b/audio/simpleaudiosample/Source/Main/SimpleAudioSample.rc
index b81a3c58..7fbb4893 100644
--- a/audio/sysvad/PhoneAudioSample/PhoneAudioSample.rc
+++ b/audio/simpleaudiosample/Source/Main/SimpleAudioSample.rc
@@ -4,11 +4,10 @@ Copyright (c) Microsoft Corporation All Rights Reserved
Module Name:
- PhoneAudioSample.rc
+ SimpleAudioSample.rc
Abstract:
-
--*/
#include <windows.h>
@@ -17,9 +16,9 @@ Abstract:
#define VER_FILETYPE VFT_DRV
#define VER_FILESUBTYPE VFT2_DRV_SOUND
-#define VER_FILEDESCRIPTION_STR "Microsoft Virtual Audio Phone Sample Driver"
-#define VER_INTERNALNAME_STR "PhoneAudioSample.sys"
-#define VER_ORIGINALFILENAME_STR "PhoneAudioSample.sys"
+#define VER_FILEDESCRIPTION_STR "Microsoft Virtual Simple Audio Sample Driver"
+#define VER_INTERNALNAME_STR "SimpleAudioSample.sys"
+#define VER_ORIGINALFILENAME_STR "SimpleAudioSample.sys"
#define VER_LEGALCOPYRIGHT_YEARS "2013"
#define VER_LEGALCOPYRIGHT_STR "Copyright (C) Microsoft Corp." VER_LEGALCOPYRIGHT_YEARS
@@ -27,4 +26,3 @@ Abstract:
#include "common.ver"
-
diff --git a/audio/simpleaudiosample/Source/Main/adapter.cpp b/audio/simpleaudiosample/Source/Main/adapter.cpp
new file mode 100644
index 00000000..105f7fde
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/adapter.cpp
@@ -0,0 +1,844 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ adapter.cpp
+
+Abstract:
+
+ Setup and miniport installation. No resources are used by simple audio sample.
+ This sample is to demonstrate how to develop a full featured audio miniport driver.
+--*/
+
+#pragma warning (disable : 4127)
+
+//
+// All the GUIDS for all the miniports end up in this object.
+//
+#define PUT_GUIDS_HERE
+
+#include "definitions.h"
+#include "endpoints.h"
+#include "minipairs.h"
+
+typedef void (*fnPcDriverUnload) (PDRIVER_OBJECT);
+fnPcDriverUnload gPCDriverUnloadRoutine = NULL;
+extern "C" DRIVER_UNLOAD DriverUnload;
+
+//-----------------------------------------------------------------------------
+// Referenced forward.
+//-----------------------------------------------------------------------------
+
+DRIVER_ADD_DEVICE AddDevice;
+
+NTSTATUS
+StartDevice
+(
+ _In_ PDEVICE_OBJECT,
+ _In_ PIRP,
+ _In_ PRESOURCELIST
+);
+
+_Dispatch_type_(IRP_MJ_PNP)
+DRIVER_DISPATCH PnpHandler;
+
+//
+// Rendering streams are saved to a file by default. Use the registry value
+// DoNotCreateDataFiles (DWORD) > 0 to override this default.
+//
+DWORD g_DoNotCreateDataFiles = 0; // default is off.
+DWORD g_DisableToneGenerator = 0; // default is to generate tones.
+UNICODE_STRING g_RegistryPath; // This is used to store the registry settings path for the driver
+
+//-----------------------------------------------------------------------------
+// Functions
+//-----------------------------------------------------------------------------
+
+#pragma code_seg("PAGE")
+void ReleaseRegistryStringBuffer()
+{
+ if (g_RegistryPath.Buffer != NULL)
+ {
+ ExFreePool(g_RegistryPath.Buffer);
+ g_RegistryPath.Buffer = NULL;
+ g_RegistryPath.Length = 0;
+ g_RegistryPath.MaximumLength = 0;
+ }
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+extern "C"
+void DriverUnload
+(
+ _In_ PDRIVER_OBJECT DriverObject
+)
+/*++
+
+Routine Description:
+
+ Our driver unload routine. This just frees the WDF driver object.
+
+Arguments:
+
+ DriverObject - pointer to the driver object
+
+Environment:
+
+ PASSIVE_LEVEL
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF(D_TERSE, ("[DriverUnload]"));
+
+ ReleaseRegistryStringBuffer();
+
+ if (DriverObject == NULL)
+ {
+ goto Done;
+ }
+
+ //
+ // Invoke first the port unload.
+ //
+ if (gPCDriverUnloadRoutine != NULL)
+ {
+ gPCDriverUnloadRoutine(DriverObject);
+ }
+
+ //
+ // Unload WDF driver object.
+ //
+ if (WdfGetDriver() != NULL)
+ {
+ WdfDriverMiniportUnload(WdfGetDriver());
+ }
+Done:
+ return;
+}
+
+//=============================================================================
+#pragma code_seg("INIT")
+__drv_requiresIRQL(PASSIVE_LEVEL)
+NTSTATUS
+CopyRegistrySettingsPath(
+ _In_ PUNICODE_STRING RegistryPath
+)
+/*++
+
+Routine Description:
+
+Copies the following registry path to a global variable.
+
+\REGISTRY\MACHINE\SYSTEM\ControlSetxxx\Services\<driver>\Parameters
+
+Arguments:
+
+RegistryPath - Registry path passed to DriverEntry
+
+Returns:
+
+NTSTATUS - SUCCESS if able to configure the framework
+
+--*/
+
+{
+ // Initializing the unicode string, so that if it is not allocated it will not be deallocated too.
+ RtlInitUnicodeString(&g_RegistryPath, NULL);
+
+ g_RegistryPath.MaximumLength = RegistryPath->Length + sizeof(WCHAR);
+
+ g_RegistryPath.Buffer = (PWCH)ExAllocatePool2(POOL_FLAG_PAGED, g_RegistryPath.MaximumLength, MINADAPTER_POOLTAG);
+
+ if (g_RegistryPath.Buffer == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlAppendUnicodeToString(&g_RegistryPath, RegistryPath->Buffer);
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("INIT")
+__drv_requiresIRQL(PASSIVE_LEVEL)
+NTSTATUS
+GetRegistrySettings(
+ _In_ PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ Initialize Driver Framework settings from the driver
+ specific registry settings under
+
+ \REGISTRY\MACHINE\SYSTEM\ControlSetxxx\Services\<driver>\Parameters
+
+Arguments:
+
+ RegistryPath - Registry path passed to DriverEntry
+
+Returns:
+
+ NTSTATUS - SUCCESS if able to configure the framework
+
+--*/
+
+{
+ NTSTATUS ntStatus;
+ UNICODE_STRING parametersPath;
+ RTL_QUERY_REGISTRY_TABLE paramTable[] = {
+ // QueryRoutine Flags Name EntryContext DefaultType DefaultData DefaultLength
+ { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK, L"DoNotCreateDataFiles", &g_DoNotCreateDataFiles, (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD, &g_DoNotCreateDataFiles, sizeof(ULONG)},
+ { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK, L"DisableToneGenerator", &g_DisableToneGenerator, (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD, &g_DisableToneGenerator, sizeof(ULONG)},
+ { NULL, 0, NULL, NULL, 0, NULL, 0}
+ };
+
+ DPF(D_TERSE, ("[GetRegistrySettings]"));
+
+ PAGED_CODE();
+
+ RtlInitUnicodeString(&parametersPath, NULL);
+
+ parametersPath.MaximumLength =
+ RegistryPath->Length + sizeof(L"\\Parameters") + sizeof(WCHAR);
+
+ parametersPath.Buffer = (PWCH) ExAllocatePool2(POOL_FLAG_PAGED, parametersPath.MaximumLength, MINADAPTER_POOLTAG);
+ if (parametersPath.Buffer == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlAppendUnicodeToString(&parametersPath, RegistryPath->Buffer);
+ RtlAppendUnicodeToString(&parametersPath, L"\\Parameters");
+
+ ntStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
+ parametersPath.Buffer,
+ &paramTable[0],
+ NULL,
+ NULL
+ );
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_VERBOSE, ("RtlQueryRegistryValues failed, using default values, 0x%x", ntStatus));
+ //
+ // Don't return error because we will operate with default values.
+ //
+ }
+
+ //
+ // Dump settings.
+ //
+ DPF(D_VERBOSE, ("DoNotCreateDataFiles: %u", g_DoNotCreateDataFiles));
+ DPF(D_VERBOSE, ("DisableToneGenerator: %u", g_DisableToneGenerator));
+
+ //
+ // Cleanup.
+ //
+ ExFreePool(parametersPath.Buffer);
+
+ return STATUS_SUCCESS;
+}
+
+#pragma code_seg("INIT")
+extern "C" DRIVER_INITIALIZE DriverEntry;
+extern "C" NTSTATUS
+DriverEntry
+(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPathName
+)
+{
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point.
+ This entry point is called directly by the I/O system.
+
+ All audio adapter drivers can use this code without change.
+
+Arguments:
+
+ DriverObject - pointer to the driver object
+
+ RegistryPath - pointer to a unicode string representing the path,
+ to driver-specific key in the registry.
+
+Return Value:
+
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise.
+
+--*/
+ NTSTATUS ntStatus;
+ WDF_DRIVER_CONFIG config;
+
+ DPF(D_TERSE, ("[DriverEntry]"));
+
+ // Copy registry Path name in a global variable to be used by modules inside driver.
+ // !! NOTE !! Inside this function we are initializing the registrypath, so we MUST NOT add any failing calls
+ // before the following call.
+ ntStatus = CopyRegistrySettingsPath(RegistryPathName);
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("Registry path copy error 0x%x", ntStatus)),
+ Done);
+
+ //
+ // Get registry configuration.
+ //
+ ntStatus = GetRegistrySettings(RegistryPathName);
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("Registry Configuration error 0x%x", ntStatus)),
+ Done);
+
+ WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
+ //
+ // Set WdfDriverInitNoDispatchOverride flag to tell the framework
+ // not to provide dispatch routines for the driver. In other words,
+ // the framework must not intercept IRPs that the I/O manager has
+ // directed to the driver. In this case, they will be handled by Audio
+ // port driver.
+ //
+ config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
+ config.DriverPoolTag = MINADAPTER_POOLTAG;
+
+ ntStatus = WdfDriverCreate(DriverObject,
+ RegistryPathName,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &config,
+ WDF_NO_HANDLE);
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("WdfDriverCreate failed, 0x%x", ntStatus)),
+ Done);
+
+ //
+ // Tell the class driver to initialize the driver.
+ //
+ ntStatus = PcInitializeAdapterDriver(DriverObject,
+ RegistryPathName,
+ (PDRIVER_ADD_DEVICE)AddDevice);
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("PcInitializeAdapterDriver failed, 0x%x", ntStatus)),
+ Done);
+
+ //
+ // To intercept stop/remove/surprise-remove.
+ //
+ DriverObject->MajorFunction[IRP_MJ_PNP] = PnpHandler;
+
+ //
+ // Hook the port class unload function
+ //
+ gPCDriverUnloadRoutine = DriverObject->DriverUnload;
+ DriverObject->DriverUnload = DriverUnload;
+
+ //
+ // All done.
+ //
+ ntStatus = STATUS_SUCCESS;
+
+Done:
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ if (WdfGetDriver() != NULL)
+ {
+ WdfDriverMiniportUnload(WdfGetDriver());
+ }
+
+ ReleaseRegistryStringBuffer();
+ }
+
+ return ntStatus;
+} // DriverEntry
+
+#pragma code_seg()
+// disable prefast warning 28152 because
+// DO_DEVICE_INITIALIZING is cleared in PcAddAdapterDevice
+#pragma warning(disable:28152)
+#pragma code_seg("PAGE")
+//=============================================================================
+NTSTATUS AddDevice
+(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PDEVICE_OBJECT PhysicalDeviceObject
+)
+/*++
+
+Routine Description:
+
+ The Plug & Play subsystem is handing us a brand new PDO, for which we
+ (by means of INF registration) have been asked to provide a driver.
+
+ We need to determine if we need to be in the driver stack for the device.
+ Create a function device object to attach to the stack
+ Initialize that device object
+ Return status success.
+
+ All audio adapter drivers can use this code without change.
+
+Arguments:
+
+ DriverObject - pointer to a driver object
+
+ PhysicalDeviceObject - pointer to a device object created by the
+ underlying bus driver.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus;
+ ULONG maxObjects;
+
+ DPF(D_TERSE, ("[AddDevice]"));
+
+ maxObjects = g_MaxMiniports;
+
+ // Tell the class driver to add the device.
+ //
+ ntStatus =
+ PcAddAdapterDevice
+ (
+ DriverObject,
+ PhysicalDeviceObject,
+ PCPFNSTARTDEVICE(StartDevice),
+ maxObjects,
+ 0
+ );
+
+ return ntStatus;
+} // AddDevice
+
+#pragma code_seg()
+NTSTATUS
+_IRQL_requires_max_(DISPATCH_LEVEL)
+PowerControlCallback
+(
+ _In_ LPCGUID PowerControlCode,
+ _In_opt_ PVOID InBuffer,
+ _In_ SIZE_T InBufferSize,
+ _Out_writes_bytes_to_(OutBufferSize, *BytesReturned) PVOID OutBuffer,
+ _In_ SIZE_T OutBufferSize,
+ _Out_opt_ PSIZE_T BytesReturned,
+ _In_opt_ PVOID Context
+)
+{
+ UNREFERENCED_PARAMETER(PowerControlCode);
+ UNREFERENCED_PARAMETER(InBuffer);
+ UNREFERENCED_PARAMETER(InBufferSize);
+ UNREFERENCED_PARAMETER(OutBuffer);
+ UNREFERENCED_PARAMETER(OutBufferSize);
+ UNREFERENCED_PARAMETER(BytesReturned);
+ UNREFERENCED_PARAMETER(Context);
+
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+#pragma code_seg("PAGE")
+NTSTATUS
+InstallEndpointRenderFilters(
+ _In_ PDEVICE_OBJECT _pDeviceObject,
+ _In_ PIRP _pIrp,
+ _In_ PADAPTERCOMMON _pAdapterCommon,
+ _In_ PENDPOINT_MINIPAIR _pAeMiniports
+ )
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ PUNKNOWN unknownTopology = NULL;
+ PUNKNOWN unknownWave = NULL;
+ PPORTCLSETWHELPER pPortClsEtwHelper = NULL;
+#ifdef _USE_IPortClsRuntimePower
+ PPORTCLSRUNTIMEPOWER pPortClsRuntimePower = NULL;
+#endif // _USE_IPortClsRuntimePower
+ PPORTCLSStreamResourceManager pPortClsResMgr = NULL;
+ PPORTCLSStreamResourceManager2 pPortClsResMgr2 = NULL;
+
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER(_pDeviceObject);
+
+ ntStatus = _pAdapterCommon->InstallEndpointFilters(
+ _pIrp,
+ _pAeMiniports,
+ NULL,
+ &unknownTopology,
+ &unknownWave,
+ NULL, NULL);
+
+ if (unknownWave) // IID_IPortClsEtwHelper and IID_IPortClsRuntimePower interfaces are only exposed on the WaveRT port.
+ {
+ ntStatus = unknownWave->QueryInterface (IID_IPortClsEtwHelper, (PVOID *)&pPortClsEtwHelper);
+ if (NT_SUCCESS(ntStatus))
+ {
+ _pAdapterCommon->SetEtwHelper(pPortClsEtwHelper);
+ ASSERT(pPortClsEtwHelper != NULL);
+ pPortClsEtwHelper->Release();
+ }
+
+#ifdef _USE_IPortClsRuntimePower
+ // Let's get the runtime power interface on PortCls.
+ ntStatus = unknownWave->QueryInterface(IID_IPortClsRuntimePower, (PVOID *)&pPortClsRuntimePower);
+ if (NT_SUCCESS(ntStatus))
+ {
+ // This interface would typically be stashed away for later use. Instead,
+ // let's just send an empty control with GUID_NULL.
+ NTSTATUS ntStatusTest =
+ pPortClsRuntimePower->SendPowerControl
+ (
+ _pDeviceObject,
+ &GUID_NULL,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ NULL
+ );
+
+ if (NT_SUCCESS(ntStatusTest) || STATUS_NOT_IMPLEMENTED == ntStatusTest || STATUS_NOT_SUPPORTED == ntStatusTest)
+ {
+ ntStatus = pPortClsRuntimePower->RegisterPowerControlCallback(_pDeviceObject, &PowerControlCallback, NULL);
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = pPortClsRuntimePower->UnregisterPowerControlCallback(_pDeviceObject);
+ }
+ }
+ else
+ {
+ ntStatus = ntStatusTest;
+ }
+
+ pPortClsRuntimePower->Release();
+ }
+#endif // _USE_IPortClsRuntimePower
+
+ //
+ // Test: add and remove current thread as streaming audio resource.
+ // In a real driver you should only add interrupts and driver-owned threads
+ // (i.e., do NOT add the current thread as streaming resource).
+ //
+ // testing IPortClsStreamResourceManager:
+ ntStatus = unknownWave->QueryInterface(IID_IPortClsStreamResourceManager, (PVOID *)&pPortClsResMgr);
+ if (NT_SUCCESS(ntStatus))
+ {
+ PCSTREAMRESOURCE_DESCRIPTOR res;
+ PCSTREAMRESOURCE hRes = NULL;
+ PDEVICE_OBJECT pdo = NULL;
+
+ PcGetPhysicalDeviceObject(_pDeviceObject, &pdo);
+ PCSTREAMRESOURCE_DESCRIPTOR_INIT(&res);
+ res.Pdo = pdo;
+ res.Type = ePcStreamResourceThread;
+ res.Resource.Thread = PsGetCurrentThread();
+
+ NTSTATUS ntStatusTest = pPortClsResMgr->AddStreamResource(NULL, &res, &hRes);
+ if (NT_SUCCESS(ntStatusTest))
+ {
+ pPortClsResMgr->RemoveStreamResource(hRes);
+ hRes = NULL;
+ }
+
+ pPortClsResMgr->Release();
+ pPortClsResMgr = NULL;
+ }
+
+ // testing IPortClsStreamResourceManager2:
+ ntStatus = unknownWave->QueryInterface(IID_IPortClsStreamResourceManager2, (PVOID *)&pPortClsResMgr2);
+ if (NT_SUCCESS(ntStatus))
+ {
+ PCSTREAMRESOURCE_DESCRIPTOR res;
+ PCSTREAMRESOURCE hRes = NULL;
+ PDEVICE_OBJECT pdo = NULL;
+
+ PcGetPhysicalDeviceObject(_pDeviceObject, &pdo);
+ PCSTREAMRESOURCE_DESCRIPTOR_INIT(&res);
+ res.Pdo = pdo;
+ res.Type = ePcStreamResourceThread;
+ res.Resource.Thread = PsGetCurrentThread();
+
+ NTSTATUS ntStatusTest = pPortClsResMgr2->AddStreamResource2(pdo, NULL, &res, &hRes);
+ if (NT_SUCCESS(ntStatusTest))
+ {
+ pPortClsResMgr2->RemoveStreamResource(hRes);
+ hRes = NULL;
+ }
+
+ pPortClsResMgr2->Release();
+ pPortClsResMgr2 = NULL;
+ }
+ }
+
+ SAFE_RELEASE(unknownTopology);
+ SAFE_RELEASE(unknownWave);
+
+ return ntStatus;
+}
+
+#pragma code_seg("PAGE")
+NTSTATUS
+InstallAllRenderFilters(
+ _In_ PDEVICE_OBJECT _pDeviceObject,
+ _In_ PIRP _pIrp,
+ _In_ PADAPTERCOMMON _pAdapterCommon
+ )
+{
+ NTSTATUS ntStatus;
+ PENDPOINT_MINIPAIR* ppAeMiniports = g_RenderEndpoints;
+
+ PAGED_CODE();
+
+ for(ULONG i = 0; i < g_cRenderEndpoints; ++i, ++ppAeMiniports)
+ {
+ ntStatus = InstallEndpointRenderFilters(_pDeviceObject, _pIrp, _pAdapterCommon, *ppAeMiniports);
+ IF_FAILED_JUMP(ntStatus, Exit);
+ }
+
+ ntStatus = STATUS_SUCCESS;
+
+Exit:
+ return ntStatus;
+}
+
+#pragma code_seg("PAGE")
+NTSTATUS
+InstallEndpointCaptureFilters(
+ _In_ PDEVICE_OBJECT _pDeviceObject,
+ _In_ PIRP _pIrp,
+ _In_ PADAPTERCOMMON _pAdapterCommon,
+ _In_ PENDPOINT_MINIPAIR _pAeMiniports
+)
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER(_pDeviceObject);
+
+ ntStatus = _pAdapterCommon->InstallEndpointFilters(
+ _pIrp,
+ _pAeMiniports,
+ NULL,
+ NULL,
+ NULL,
+ NULL, NULL);
+
+ return ntStatus;
+}
+
+#pragma code_seg("PAGE")
+NTSTATUS
+InstallAllCaptureFilters(
+ _In_ PDEVICE_OBJECT _pDeviceObject,
+ _In_ PIRP _pIrp,
+ _In_ PADAPTERCOMMON _pAdapterCommon
+)
+{
+ NTSTATUS ntStatus;
+ PENDPOINT_MINIPAIR* ppAeMiniports = g_CaptureEndpoints;
+
+ PAGED_CODE();
+
+ for (ULONG i = 0; i < g_cCaptureEndpoints; ++i, ++ppAeMiniports)
+ {
+ ntStatus = InstallEndpointCaptureFilters(_pDeviceObject, _pIrp, _pAdapterCommon, *ppAeMiniports);
+ IF_FAILED_JUMP(ntStatus, Exit);
+ }
+
+ ntStatus = STATUS_SUCCESS;
+
+Exit:
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+StartDevice
+(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp,
+ _In_ PRESOURCELIST ResourceList
+)
+{
+/*++
+
+Routine Description:
+
+ This function is called by the operating system when the device is
+ started.
+ It is responsible for starting the miniports. This code is specific to
+ the adapter because it calls out miniports for functions that are specific
+ to the adapter.
+
+Arguments:
+
+ DeviceObject - pointer to the driver object
+
+ Irp - pointer to the irp
+
+ ResourceList - pointer to the resource list assigned by PnP manager
+
+Return Value:
+
+ NT status code.
+
+--*/
+ UNREFERENCED_PARAMETER(ResourceList);
+
+ PAGED_CODE();
+
+ ASSERT(DeviceObject);
+ ASSERT(Irp);
+ ASSERT(ResourceList);
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ PADAPTERCOMMON pAdapterCommon = NULL;
+ PUNKNOWN pUnknownCommon = NULL;
+ PortClassDeviceContext* pExtension = static_cast<PortClassDeviceContext*>(DeviceObject->DeviceExtension);
+
+ DPF_ENTER(("[StartDevice]"));
+
+ //
+ // create a new adapter common object
+ //
+ ntStatus = NewAdapterCommon(
+ &pUnknownCommon,
+ IID_IAdapterCommon,
+ NULL,
+ POOL_FLAG_NON_PAGED
+ );
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+ ntStatus = pUnknownCommon->QueryInterface( IID_IAdapterCommon,(PVOID *) &pAdapterCommon);
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+ ntStatus = pAdapterCommon->Init(DeviceObject);
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+ //
+ // register with PortCls for power-management services
+ ntStatus = PcRegisterAdapterPowerManagement( PUNKNOWN(pAdapterCommon), DeviceObject);
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+ //
+ // Install wave+topology filters for render devices
+ //
+ ntStatus = InstallAllRenderFilters(DeviceObject, Irp, pAdapterCommon);
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+ //
+ // Install wave+topology filters for capture devices
+ //
+ ntStatus = InstallAllCaptureFilters(DeviceObject, Irp, pAdapterCommon);
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+Exit:
+
+ //
+ // Stash the adapter common object in the device extension so
+ // we can access it for cleanup on stop/removal.
+ //
+ if (pAdapterCommon)
+ {
+ ASSERT(pExtension != NULL);
+ pExtension->m_pCommon = pAdapterCommon;
+ }
+
+ //
+ // Release the adapter IUnknown interface.
+ //
+ SAFE_RELEASE(pUnknownCommon);
+
+ return ntStatus;
+} // StartDevice
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+PnpHandler
+(
+ _In_ DEVICE_OBJECT *_DeviceObject,
+ _Inout_ IRP *_Irp
+)
+/*++
+
+Routine Description:
+
+ Handles PnP IRPs
+
+Arguments:
+
+ _DeviceObject - Functional Device object pointer.
+
+ _Irp - The Irp being passed
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
+ IO_STACK_LOCATION *stack;
+ PortClassDeviceContext *ext;
+
+ // Documented https://msdn.microsoft.com/en-us/library/windows/hardware/ff544039(v=vs.85).aspx
+ // This method will be called in IRQL PASSIVE_LEVEL
+#pragma warning(suppress: 28118)
+ PAGED_CODE();
+
+ ASSERT(_DeviceObject);
+ ASSERT(_Irp);
+
+ //
+ // Check for the REMOVE_DEVICE irp. If we're being unloaded,
+ // uninstantiate our devices and release the adapter common
+ // object.
+ //
+ stack = IoGetCurrentIrpStackLocation(_Irp);
+
+ switch (stack->MinorFunction)
+ {
+ case IRP_MN_REMOVE_DEVICE:
+ case IRP_MN_SURPRISE_REMOVAL:
+ case IRP_MN_STOP_DEVICE:
+ ext = static_cast<PortClassDeviceContext*>(_DeviceObject->DeviceExtension);
+
+ if (ext->m_pCommon != NULL)
+ {
+ ext->m_pCommon->Cleanup();
+
+ ext->m_pCommon->Release();
+ ext->m_pCommon = NULL;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ ntStatus = PcDispatchIrp(_DeviceObject, _Irp);
+
+ return ntStatus;
+}
+
+#pragma code_seg()
+
diff --git a/audio/simpleaudiosample/Source/Main/basetopo.cpp b/audio/simpleaudiosample/Source/Main/basetopo.cpp
new file mode 100644
index 00000000..b29a9bb1
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/basetopo.cpp
@@ -0,0 +1,688 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ basetopo.cpp
+
+Abstract:
+
+ Implementation of topology miniport. This the base class for
+ all simple audio sample drivers
+--*/
+
+//4127: conditional expression is constant
+#pragma warning (disable : 4127)
+
+#include "definitions.h"
+#include "basetopo.h"
+
+//=============================================================================
+#pragma code_seg("PAGE")
+CMiniportTopologySimpleAudioSample::CMiniportTopologySimpleAudioSample
+(
+ _In_ PCFILTER_DESCRIPTOR *FilterDesc,
+ _In_ USHORT DeviceMaxChannels
+)
+/*++
+
+Routine Description:
+
+ Topology miniport constructor
+
+Arguments:
+
+ FilterDesc -
+
+ DeviceMaxChannels -
+
+Return Value:
+
+ void
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[%s]",__FUNCTION__));
+
+ m_AdapterCommon = NULL;
+
+ ASSERT(FilterDesc != NULL);
+ m_FilterDescriptor = FilterDesc;
+ m_PortEvents = NULL;
+
+ ASSERT(DeviceMaxChannels > 0);
+ m_DeviceMaxChannels = DeviceMaxChannels;
+} // CMiniportTopologySimpleAudioSample
+
+CMiniportTopologySimpleAudioSample::~CMiniportTopologySimpleAudioSample
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Topology miniport destructor
+
+Arguments:
+
+Return Value:
+
+ void
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[%s]",__FUNCTION__));
+
+ SAFE_RELEASE(m_AdapterCommon);
+ SAFE_RELEASE(m_PortEvents);
+} // ~CMiniportTopologySimpleAudioSample
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportTopologySimpleAudioSample::DataRangeIntersection
+(
+ _In_ ULONG PinId,
+ _In_ PKSDATARANGE ClientDataRange,
+ _In_ PKSDATARANGE MyDataRange,
+ _In_ ULONG OutputBufferLength,
+ _Out_writes_bytes_to_opt_(OutputBufferLength, *ResultantFormatLength)
+ PVOID ResultantFormat OPTIONAL,
+ _Out_ PULONG ResultantFormatLength
+)
+/*++
+
+Routine Description:
+
+ The DataRangeIntersection function determines the highest
+ quality intersection of two data ranges. Topology miniport does nothing.
+
+Arguments:
+
+ PinId - Pin for which data intersection is being determined.
+
+ ClientDataRange - Pointer to KSDATARANGE structure which contains the data range
+ submitted by client in the data range intersection property
+ request
+
+ MyDataRange - Pin's data range to be compared with client's data range
+
+ OutputBufferLength - Size of the buffer pointed to by the resultant format
+ parameter
+
+ ResultantFormat - Pointer to value where the resultant format should be
+ returned
+
+ ResultantFormatLength - Actual length of the resultant format that is placed
+ at ResultantFormat. This should be less than or equal
+ to OutputBufferLength
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(PinId);
+ UNREFERENCED_PARAMETER(ClientDataRange);
+ UNREFERENCED_PARAMETER(MyDataRange);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+ UNREFERENCED_PARAMETER(ResultantFormat);
+ UNREFERENCED_PARAMETER(ResultantFormatLength);
+
+ PAGED_CODE();
+
+ DPF_ENTER(("[%s]",__FUNCTION__));
+
+ return (STATUS_NOT_IMPLEMENTED);
+} // DataRangeIntersection
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportTopologySimpleAudioSample::GetDescription
+(
+ _Out_ PPCFILTER_DESCRIPTOR * OutFilterDescriptor
+)
+/*++
+
+Routine Description:
+
+ The GetDescription function gets a pointer to a filter description.
+ It provides a location to deposit a pointer in miniport's description
+ structure. This is the placeholder for the FromNode or ToNode fields in
+ connections which describe connections to the filter's pins
+
+Arguments:
+
+ OutFilterDescriptor - Pointer to the filter description.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(OutFilterDescriptor);
+
+ DPF_ENTER(("[%s]",__FUNCTION__));
+
+ *OutFilterDescriptor = m_FilterDescriptor;
+
+ return (STATUS_SUCCESS);
+} // GetDescription
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportTopologySimpleAudioSample::Init
+(
+ _In_ PUNKNOWN UnknownAdapter_,
+ _In_ PPORTTOPOLOGY Port_
+)
+/*++
+
+Routine Description:
+
+ Initializes the topology miniport.
+
+Arguments:
+
+ UnknownAdapter -
+
+ Port_ - Pointer to topology port
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(UnknownAdapter_);
+ ASSERT(Port_);
+
+ DPF_ENTER(("[CMiniportTopologySimpleAudioSample::Init]"));
+
+ NTSTATUS ntStatus;
+
+ ntStatus =
+ UnknownAdapter_->QueryInterface(
+ IID_IAdapterCommon,
+ (PVOID *) &m_AdapterCommon);
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ //
+ // Get the port event interface.
+ //
+ ntStatus = Port_->QueryInterface(
+ IID_IPortEvents,
+ (PVOID *)&m_PortEvents);
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ m_AdapterCommon->MixerReset();
+ }
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ // clean up AdapterCommon
+ SAFE_RELEASE(m_AdapterCommon);
+ SAFE_RELEASE(m_PortEvents);
+ }
+
+ return ntStatus;
+} // Init
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportTopologySimpleAudioSample::PropertyHandlerGeneric
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Handles all properties for this miniport.
+
+Arguments:
+
+ PropertyRequest - property request structure
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+
+ switch (PropertyRequest->PropertyItem->Id)
+ {
+ case KSPROPERTY_AUDIO_VOLUMELEVEL:
+ ntStatus = PropertyHandler_Volume(
+ m_AdapterCommon,
+ PropertyRequest,
+ m_DeviceMaxChannels);
+ break;
+
+ case KSPROPERTY_AUDIO_MUTE:
+ ntStatus = PropertyHandler_Mute(
+ m_AdapterCommon,
+ PropertyRequest,
+ m_DeviceMaxChannels);
+ break;
+
+ case KSPROPERTY_AUDIO_PEAKMETER2:
+ ntStatus = PropertyHandler_PeakMeter2(
+ m_AdapterCommon,
+ PropertyRequest,
+ m_DeviceMaxChannels);
+ break;
+
+ case KSPROPERTY_AUDIO_CPU_RESOURCES:
+ ntStatus = PropertyHandler_CpuResources(PropertyRequest);
+ break;
+
+ case KSPROPERTY_AUDIO_MUX_SOURCE:
+ ntStatus = PropertyHandlerMuxSource(PropertyRequest);
+ break;
+
+ case KSPROPERTY_AUDIO_DEV_SPECIFIC:
+ ntStatus = PropertyHandlerDevSpecific(PropertyRequest);
+ break;
+
+ default:
+ DPF(D_TERSE, ("[PropertyHandlerGeneric: Invalid Device Request]"));
+ }
+
+ return ntStatus;
+} // PropertyHandlerGeneric
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportTopologySimpleAudioSample::PropertyHandlerMuxSource
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ PropertyHandler for KSPROPERTY_AUDIO_MUX_SOURCE.
+
+Arguments:
+
+ PropertyRequest - property request structure
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[%s]",__FUNCTION__));
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+
+ //
+ // Validate node
+ // This property is only valid for WAVEIN_MUX node.
+ //
+ // TODO if (WAVEIN_MUX == PropertyRequest->Node)
+ {
+ if (PropertyRequest->ValueSize >= sizeof(ULONG))
+ {
+ PULONG pulMuxValue = PULONG(PropertyRequest->Value);
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ *pulMuxValue = m_AdapterCommon->MixerMuxRead();
+ PropertyRequest->ValueSize = sizeof(ULONG);
+ ntStatus = STATUS_SUCCESS;
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ m_AdapterCommon->MixerMuxWrite(*pulMuxValue);
+ ntStatus = STATUS_SUCCESS;
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ntStatus =
+ PropertyHandler_BasicSupport
+ (
+ PropertyRequest,
+ KSPROPERTY_TYPE_ALL,
+ VT_I4
+ );
+ }
+ }
+ else
+ {
+ DPF(D_TERSE, ("[PropertyHandlerMuxSource - Invalid parameter]"));
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ return ntStatus;
+} // PropertyHandlerMuxSource
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportTopologySimpleAudioSample::PropertyHandlerDevSpecific(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Property handler for KSPROPERTY_AUDIO_DEV_SPECIFIC
+
+Arguments:
+
+ PropertyRequest - property request structure
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[%s]",__FUNCTION__));
+
+ NTSTATUS ntStatus=STATUS_SUCCESS;
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ if( DEV_SPECIFIC_VT_BOOL == PropertyRequest->Node )
+ {
+ ntStatus = PropertyHandler_BasicSupport(PropertyRequest,KSPROPERTY_TYPE_ALL,VT_BOOL);
+ }
+ else
+ {
+ ULONG ExpectedSize = sizeof( KSPROPERTY_DESCRIPTION ) +
+ sizeof( KSPROPERTY_MEMBERSHEADER ) +
+ sizeof( KSPROPERTY_BOUNDS_LONG );
+ DWORD ulPropTypeSetId;
+
+ if( DEV_SPECIFIC_VT_I4 == PropertyRequest->Node )
+ {
+ ulPropTypeSetId = VT_I4;
+ }
+ else if ( DEV_SPECIFIC_VT_UI4 == PropertyRequest->Node )
+ {
+ ulPropTypeSetId = VT_UI4;
+ }
+ else
+ {
+ ulPropTypeSetId = VT_ILLEGAL;
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ if( NT_SUCCESS(ntStatus))
+ {
+ if ( !PropertyRequest->ValueSize )
+ {
+ PropertyRequest->ValueSize = ExpectedSize;
+ ntStatus = STATUS_BUFFER_OVERFLOW;
+ }
+ else if (PropertyRequest->ValueSize >= sizeof(KSPROPERTY_DESCRIPTION))
+ {
+ // if return buffer can hold a KSPROPERTY_DESCRIPTION, return it
+ //
+ PKSPROPERTY_DESCRIPTION PropDesc = PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
+
+ PropDesc->AccessFlags = KSPROPERTY_TYPE_ALL;
+ PropDesc->DescriptionSize = ExpectedSize;
+ PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General;
+ PropDesc->PropTypeSet.Id = ulPropTypeSetId;
+ PropDesc->PropTypeSet.Flags = 0;
+ PropDesc->MembersListCount = 0;
+ PropDesc->Reserved = 0;
+
+ if ( PropertyRequest->ValueSize >= ExpectedSize )
+ {
+ // Extra information to return
+ PropDesc->MembersListCount = 1;
+
+ PKSPROPERTY_MEMBERSHEADER MembersHeader = ( PKSPROPERTY_MEMBERSHEADER )( PropDesc + 1);
+ MembersHeader->MembersFlags = KSPROPERTY_MEMBER_RANGES;
+ MembersHeader->MembersCount = 1;
+ MembersHeader->MembersSize = sizeof( KSPROPERTY_BOUNDS_LONG );
+ MembersHeader->Flags = 0;
+
+ PKSPROPERTY_BOUNDS_LONG PeakMeterBounds = (PKSPROPERTY_BOUNDS_LONG)( MembersHeader + 1);
+ if(VT_I4 == ulPropTypeSetId )
+ {
+ PeakMeterBounds->SignedMinimum = 0;
+ PeakMeterBounds->SignedMaximum = 0x7fffffff;
+ }
+ else
+ {
+ PeakMeterBounds->UnsignedMinimum = 0;
+ PeakMeterBounds->UnsignedMaximum = 0xffffffff;
+ }
+
+ // set the return value size
+ PropertyRequest->ValueSize = ExpectedSize;
+ }
+ else
+ {
+ // No extra information to return.
+ PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION);
+ }
+
+ ntStatus = STATUS_SUCCESS;
+ }
+ else if (PropertyRequest->ValueSize >= sizeof(ULONG))
+ {
+ // if return buffer can hold a ULONG, return the access flags
+ //
+ *(PULONG(PropertyRequest->Value)) = KSPROPERTY_TYPE_ALL;
+
+ PropertyRequest->ValueSize = sizeof(ULONG);
+ ntStatus = STATUS_SUCCESS;
+ }
+ else
+ {
+ PropertyRequest->ValueSize = 0;
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+ }
+ }
+ else
+ {
+ // switch on node id
+ switch( PropertyRequest->Node )
+ {
+ case DEV_SPECIFIC_VT_BOOL:
+ {
+ PBOOL pbDevSpecific;
+
+ ntStatus = ValidatePropertyParams(PropertyRequest, sizeof(BOOL), 0);
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ pbDevSpecific = PBOOL (PropertyRequest->Value);
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ *pbDevSpecific = m_AdapterCommon->bDevSpecificRead();
+ PropertyRequest->ValueSize = sizeof(BOOL);
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ m_AdapterCommon->bDevSpecificWrite(*pbDevSpecific);
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+ break;
+ case DEV_SPECIFIC_VT_I4:
+ {
+ INT* piDevSpecific;
+
+ ntStatus = ValidatePropertyParams(PropertyRequest, sizeof(int), 0);
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ piDevSpecific = PINT (PropertyRequest->Value);
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ *piDevSpecific = m_AdapterCommon->iDevSpecificRead();
+ PropertyRequest->ValueSize = sizeof(int);
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ m_AdapterCommon->iDevSpecificWrite(*piDevSpecific);
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+ break;
+ case DEV_SPECIFIC_VT_UI4:
+ {
+ UINT* puiDevSpecific;
+
+ ntStatus = ValidatePropertyParams(PropertyRequest, sizeof(UINT), 0);
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ puiDevSpecific = PUINT (PropertyRequest->Value);
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ *puiDevSpecific = m_AdapterCommon->uiDevSpecificRead();
+ PropertyRequest->ValueSize = sizeof(UINT);
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ m_AdapterCommon->uiDevSpecificWrite(*puiDevSpecific);
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+ break;
+ default:
+ ntStatus = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+
+ if( !NT_SUCCESS(ntStatus))
+ {
+ DPF(D_TERSE, ("[%s - ntStatus=0x%08x]",__FUNCTION__,ntStatus));
+ }
+ }
+
+ return ntStatus;
+} // PropertyHandlerDevSpecific
+
+//=============================================================================
+#pragma code_seg("PAGE")
+VOID
+CMiniportTopologySimpleAudioSample::AddEventToEventList
+(
+ _In_ PKSEVENT_ENTRY EventEntry
+)
+/*++
+
+Routine Description:
+
+ The AddEventToEventList method adds an event to the port driver's event list
+
+Arguments:
+
+ EventEntry -
+
+--*/
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CMiniportTopology::AddEventToEventList]"));
+
+ ASSERT(m_PortEvents != NULL);
+
+ m_PortEvents->AddEventToEventList(EventEntry);
+}
+
+//=============================================================================
+#pragma code_seg()
+VOID
+CMiniportTopologySimpleAudioSample::GenerateEventList
+(
+ _In_opt_ GUID *Set,
+ _In_ ULONG EventId,
+ _In_ BOOL PinEvent,
+ _In_ ULONG PinId,
+ _In_ BOOL NodeEvent,
+ _In_ ULONG NodeId
+)
+/*++
+
+Routine Description:
+
+ The GenerateEventList method notifies clients through the port driver's list
+ of event entries that a particular event has occurred.
+
+Arguments:
+
+ Set -
+
+ EventId -
+
+ PinEvent -
+
+ PinId -
+
+ NodeEvent -
+
+ NodeId -
+
+--*/
+{
+ DPF_ENTER(("[CMiniportTopologySimpleAudioSample::GenerateEventList]"));
+
+ ASSERT(m_PortEvents != NULL);
+
+ m_PortEvents->GenerateEventList(
+ Set,
+ EventId,
+ PinEvent,
+ PinId,
+ NodeEvent,
+ NodeId);
+}
+
+#pragma code_seg()
diff --git a/audio/simpleaudiosample/Source/Main/common.cpp b/audio/simpleaudiosample/Source/Main/common.cpp
new file mode 100644
index 00000000..8843d3a4
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/common.cpp
@@ -0,0 +1,2772 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ common.cpp
+
+Abstract:
+
+ Implementation of the AdapterCommon class.
+--*/
+
+#pragma warning (disable : 4127)
+
+#include <initguid.h>
+#include "definitions.h"
+#include "hw.h"
+#include "savedata.h"
+#include "endpoints.h"
+
+//-----------------------------------------------------------------------------
+// CSaveData statics
+//-----------------------------------------------------------------------------
+
+PSAVEWORKER_PARAM CSaveData::m_pWorkItems = NULL;
+PDEVICE_OBJECT CSaveData::m_pDeviceObject = NULL;
+//=============================================================================
+// Classes
+//=============================================================================
+
+///////////////////////////////////////////////////////////////////////////////
+// CAdapterCommon
+//
+class CAdapterCommon :
+ public IAdapterCommon,
+ public IAdapterPowerManagement,
+ public CUnknown
+{
+ private:
+ PSERVICEGROUP m_pServiceGroupWave;
+ PDEVICE_OBJECT m_pDeviceObject;
+ PDEVICE_OBJECT m_pPhysicalDeviceObject;
+ WDFDEVICE m_WdfDevice; // Wdf device.
+ DEVICE_POWER_STATE m_PowerState;
+
+ PCSimpleAudioSampleHW m_pHW; // Virtual Simple Audio Sample HW object
+ PPORTCLSETWHELPER m_pPortClsEtwHelper;
+
+ static LONG m_AdapterInstances; // # of adapter objects.
+
+ DWORD m_dwIdleRequests;
+
+ public:
+ //=====================================================================
+ // Default CUnknown
+ DECLARE_STD_UNKNOWN();
+ DEFINE_STD_CONSTRUCTOR(CAdapterCommon);
+ ~CAdapterCommon();
+
+ //=====================================================================
+ // Default IAdapterPowerManagement
+ IMP_IAdapterPowerManagement;
+
+ //=====================================================================
+ // IAdapterCommon methods
+
+ STDMETHODIMP_(NTSTATUS) Init
+ (
+ _In_ PDEVICE_OBJECT DeviceObject
+ );
+
+ STDMETHODIMP_(PDEVICE_OBJECT) GetDeviceObject(void);
+
+ STDMETHODIMP_(PDEVICE_OBJECT) GetPhysicalDeviceObject(void);
+
+ STDMETHODIMP_(WDFDEVICE) GetWdfDevice(void);
+
+ STDMETHODIMP_(void) SetWaveServiceGroup
+ (
+ _In_ PSERVICEGROUP ServiceGroup
+ );
+
+ STDMETHODIMP_(BOOL) bDevSpecificRead();
+
+ STDMETHODIMP_(void) bDevSpecificWrite
+ (
+ _In_ BOOL bDevSpecific
+ );
+ STDMETHODIMP_(INT) iDevSpecificRead();
+
+ STDMETHODIMP_(void) iDevSpecificWrite
+ (
+ _In_ INT iDevSpecific
+ );
+ STDMETHODIMP_(UINT) uiDevSpecificRead();
+
+ STDMETHODIMP_(void) uiDevSpecificWrite
+ (
+ _In_ UINT uiDevSpecific
+ );
+
+ STDMETHODIMP_(BOOL) MixerMuteRead
+ (
+ _In_ ULONG Index,
+ _In_ ULONG Channel
+ );
+
+ STDMETHODIMP_(void) MixerMuteWrite
+ (
+ _In_ ULONG Index,
+ _In_ ULONG Channel,
+ _In_ BOOL Value
+ );
+
+ STDMETHODIMP_(ULONG) MixerMuxRead(void);
+
+ STDMETHODIMP_(void) MixerMuxWrite
+ (
+ _In_ ULONG Index
+ );
+
+ STDMETHODIMP_(void) MixerReset(void);
+
+ STDMETHODIMP_(LONG) MixerVolumeRead
+ (
+ _In_ ULONG Index,
+ _In_ ULONG Channel
+ );
+
+ STDMETHODIMP_(void) MixerVolumeWrite
+ (
+ _In_ ULONG Index,
+ _In_ ULONG Channel,
+ _In_ LONG Value
+ );
+
+ STDMETHODIMP_(LONG) MixerPeakMeterRead
+ (
+ _In_ ULONG Index,
+ _In_ ULONG Channel
+ );
+
+ STDMETHODIMP_(NTSTATUS) WriteEtwEvent
+ (
+ _In_ EPcMiniportEngineEvent miniportEventType,
+ _In_ ULONGLONG ullData1,
+ _In_ ULONGLONG ullData2,
+ _In_ ULONGLONG ullData3,
+ _In_ ULONGLONG ullData4
+ );
+
+ STDMETHODIMP_(VOID) SetEtwHelper
+ (
+ PPORTCLSETWHELPER _pPortClsEtwHelper
+ );
+
+ STDMETHODIMP_(NTSTATUS) InstallSubdevice
+ (
+ _In_opt_ PIRP Irp,
+ _In_ PWSTR Name,
+ _In_opt_ PWSTR TemplateName,
+ _In_ REFGUID PortClassId,
+ _In_ REFGUID MiniportClassId,
+ _In_opt_ PFNCREATEMINIPORT MiniportCreate,
+ _In_ ULONG cPropertyCount,
+ _In_reads_opt_(cPropertyCount) const SIMPLEAUDIOSAMPLE_DEVPROPERTY * pProperties,
+ _In_opt_ PVOID DeviceContext,
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_opt_ PRESOURCELIST ResourceList,
+ _In_ REFGUID PortInterfaceId,
+ _Out_opt_ PUNKNOWN * OutPortInterface,
+ _Out_opt_ PUNKNOWN * OutPortUnknown,
+ _Out_opt_ PUNKNOWN * OutMiniportUnknown
+ );
+
+ STDMETHODIMP_(NTSTATUS) UnregisterSubdevice
+ (
+ _In_opt_ PUNKNOWN UnknownPort
+ );
+
+ STDMETHODIMP_(NTSTATUS) ConnectTopologies
+ (
+ _In_ PUNKNOWN UnknownTopology,
+ _In_ PUNKNOWN UnknownWave,
+ _In_ PHYSICALCONNECTIONTABLE* PhysicalConnections,
+ _In_ ULONG PhysicalConnectionCount
+ );
+
+ STDMETHODIMP_(NTSTATUS) DisconnectTopologies
+ (
+ _In_ PUNKNOWN UnknownTopology,
+ _In_ PUNKNOWN UnknownWave,
+ _In_ PHYSICALCONNECTIONTABLE* PhysicalConnections,
+ _In_ ULONG PhysicalConnectionCount
+ );
+
+ STDMETHODIMP_(NTSTATUS) InstallEndpointFilters
+ (
+ _In_opt_ PIRP Irp,
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_opt_ PVOID DeviceContext,
+ _Out_opt_ PUNKNOWN * UnknownTopology,
+ _Out_opt_ PUNKNOWN * UnknownWave,
+ _Out_opt_ PUNKNOWN * UnknownMiniportTopology,
+ _Out_opt_ PUNKNOWN * UnknownMiniportWave
+ );
+
+ STDMETHODIMP_(NTSTATUS) RemoveEndpointFilters
+ (
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_opt_ PUNKNOWN UnknownTopology,
+ _In_opt_ PUNKNOWN UnknownWave
+ );
+
+ STDMETHODIMP_(NTSTATUS) GetFilters
+ (
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _Out_opt_ PUNKNOWN *UnknownTopologyPort,
+ _Out_opt_ PUNKNOWN *UnknownTopologyMiniport,
+ _Out_opt_ PUNKNOWN *UnknownWavePort,
+ _Out_opt_ PUNKNOWN *UnknownWaveMiniport
+ );
+
+ STDMETHODIMP_(NTSTATUS) SetIdlePowerManagement
+ (
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_ BOOL bEnabled
+ );
+
+ STDMETHODIMP_(VOID) Cleanup();
+
+ //=====================================================================
+ // friends
+ friend NTSTATUS NewAdapterCommon
+ (
+ _Out_ PUNKNOWN * Unknown,
+ _In_ REFCLSID,
+ _In_opt_ PUNKNOWN UnknownOuter,
+ _In_ POOL_FLAGS PoolFlags
+ );
+
+ private:
+
+ LIST_ENTRY m_SubdeviceCache;
+
+ NTSTATUS GetCachedSubdevice
+ (
+ _In_ PWSTR Name,
+ _Out_opt_ PUNKNOWN *OutUnknownPort,
+ _Out_opt_ PUNKNOWN *OutUnknownMiniport
+ );
+
+ NTSTATUS CacheSubdevice
+ (
+ _In_ PWSTR Name,
+ _In_ PUNKNOWN UnknownPort,
+ _In_ PUNKNOWN UnknownMiniport
+ );
+
+ NTSTATUS RemoveCachedSubdevice
+ (
+ _In_ PWSTR Name
+ );
+
+ VOID EmptySubdeviceCache();
+
+ NTSTATUS CreateAudioInterfaceWithProperties
+ (
+ _In_ PCWSTR ReferenceString,
+ _In_opt_ PCWSTR TemplateReferenceString,
+ _In_ ULONG cPropertyCount,
+ _In_reads_opt_(cPropertyCount) const SIMPLEAUDIOSAMPLE_DEVPROPERTY *pProperties,
+ _Out_ _At_(AudioSymbolicLinkName->Buffer, __drv_allocatesMem(Mem)) PUNICODE_STRING AudioSymbolicLinkName
+ );
+
+ NTSTATUS MigrateDeviceInterfaceTemplateParameters
+ (
+ _In_ PUNICODE_STRING SymbolicLinkName,
+ _In_opt_ PCWSTR TemplateReferenceString
+ );
+};
+
+typedef struct _MINIPAIR_UNKNOWN
+{
+ LIST_ENTRY ListEntry;
+ WCHAR Name[MAX_PATH];
+ PUNKNOWN PortInterface;
+ PUNKNOWN MiniportInterface;
+ PADAPTERPOWERMANAGEMENT PowerInterface;
+} MINIPAIR_UNKNOWN;
+
+#define MAX_DEVICE_REG_KEY_LENGTH 0x100
+
+//
+// Used to implement the singleton pattern.
+//
+LONG CAdapterCommon::m_AdapterInstances = 0;
+
+
+
+//-----------------------------------------------------------------------------
+// Functions
+//-----------------------------------------------------------------------------
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS SimpleAudioSampleIoSetDeviceInterfacePropertyDataMultiple
+(
+ _In_ PUNICODE_STRING SymbolicLinkName,
+ _In_ ULONG cPropertyCount,
+ _In_reads_opt_(cPropertyCount) const SIMPLEAUDIOSAMPLE_DEVPROPERTY *pProperties
+)
+{
+ NTSTATUS ntStatus;
+
+ PAGED_CODE();
+
+ if (pProperties)
+ {
+ for (ULONG i = 0; i < cPropertyCount; i++)
+ {
+ ntStatus = IoSetDeviceInterfacePropertyData(
+ SymbolicLinkName,
+ pProperties[i].PropertyKey,
+ LOCALE_NEUTRAL,
+ PLUGPLAY_PROPERTY_PERSISTENT,
+ pProperties[i].Type,
+ pProperties[i].BufferSize,
+ pProperties[i].Buffer);
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return ntStatus;
+ }
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+NewAdapterCommon
+(
+ _Out_ PUNKNOWN * Unknown,
+ _In_ REFCLSID,
+ _In_opt_ PUNKNOWN UnknownOuter,
+ _In_ POOL_FLAGS PoolFlags
+)
+/*++
+
+Routine Description:
+
+ Creates a new CAdapterCommon
+
+Arguments:
+
+ Unknown -
+
+ UnknownOuter -
+
+ PoolType
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(Unknown);
+
+ NTSTATUS ntStatus;
+
+ //
+ // This sample supports only one instance of this object.
+ // (b/c of CSaveData's static members and Bluetooth HFP logic).
+ //
+ if (InterlockedCompareExchange(&CAdapterCommon::m_AdapterInstances, 1, 0) != 0)
+ {
+ ntStatus = STATUS_DEVICE_BUSY;
+ DPF(D_ERROR, ("NewAdapterCommon failed, only one instance is allowed"));
+ goto Done;
+ }
+
+ //
+ // Allocate an adapter object.
+ //
+ CAdapterCommon *p = new(PoolFlags, MINADAPTER_POOLTAG) CAdapterCommon(UnknownOuter);
+ if (p == NULL)
+ {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ DPF(D_ERROR, ("NewAdapterCommon failed, 0x%x", ntStatus));
+ goto Done;
+ }
+
+ //
+ // Success.
+ //
+ *Unknown = PUNKNOWN((PADAPTERCOMMON)(p));
+ (*Unknown)->AddRef();
+ ntStatus = STATUS_SUCCESS;
+
+Done:
+ return ntStatus;
+} // NewAdapterCommon
+
+//=============================================================================
+#pragma code_seg("PAGE")
+CAdapterCommon::~CAdapterCommon
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Destructor for CAdapterCommon.
+
+Arguments:
+
+Return Value:
+
+ void
+
+--*/
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::~CAdapterCommon]"));
+
+ if (m_pHW)
+ {
+ delete m_pHW;
+ m_pHW = NULL;
+ }
+
+ CSaveData::DestroyWorkItems();
+ SAFE_RELEASE(m_pPortClsEtwHelper);
+ SAFE_RELEASE(m_pServiceGroupWave);
+
+ if (m_WdfDevice)
+ {
+ WdfObjectDelete(m_WdfDevice);
+ m_WdfDevice = NULL;
+ }
+
+ InterlockedDecrement(&CAdapterCommon::m_AdapterInstances);
+ ASSERT(CAdapterCommon::m_AdapterInstances == 0);
+} // ~CAdapterCommon
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(PDEVICE_OBJECT)
+CAdapterCommon::GetDeviceObject
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Returns the deviceobject
+
+Arguments:
+
+Return Value:
+
+ PDEVICE_OBJECT
+
+--*/
+{
+ PAGED_CODE();
+
+ return m_pDeviceObject;
+} // GetDeviceObject
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(PDEVICE_OBJECT)
+CAdapterCommon::GetPhysicalDeviceObject
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Returns the PDO.
+
+Arguments:
+
+Return Value:
+
+ PDEVICE_OBJECT
+
+--*/
+{
+ PAGED_CODE();
+
+ return m_pPhysicalDeviceObject;
+} // GetPhysicalDeviceObject
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(WDFDEVICE)
+CAdapterCommon::GetWdfDevice
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Returns the associated WDF miniport device. Note that this is NOT an audio
+ miniport. The WDF miniport device is the WDF device associated with the
+ adapter.
+
+Arguments:
+
+Return Value:
+
+ WDFDEVICE
+
+--*/
+{
+ PAGED_CODE();
+
+ return m_WdfDevice;
+} // GetWdfDevice
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CAdapterCommon::Init
+(
+ _In_ PDEVICE_OBJECT DeviceObject
+)
+/*++
+
+Routine Description:
+
+ Initialize adapter common object.
+
+Arguments:
+
+ DeviceObject - pointer to the device object
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::Init]"));
+
+ ASSERT(DeviceObject);
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ m_pServiceGroupWave = NULL;
+ m_pDeviceObject = DeviceObject;
+ m_pPhysicalDeviceObject = NULL;
+ m_WdfDevice = NULL;
+ m_PowerState = PowerDeviceD0;
+ m_pHW = NULL;
+ m_pPortClsEtwHelper = NULL;
+
+ InitializeListHead(&m_SubdeviceCache);
+
+ //
+ // Get the PDO.
+ //
+ ntStatus = PcGetPhysicalDeviceObject(DeviceObject, &m_pPhysicalDeviceObject);
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("PcGetPhysicalDeviceObject failed, 0x%x", ntStatus)),
+ Done);
+
+ //
+ // Create a WDF miniport to represent the adapter. Note that WDF miniports
+ // are NOT audio miniports. An audio adapter is associated with a single WDF
+ // miniport. This driver uses WDF to simplify the handling of the Bluetooth
+ // SCO HFP Bypass interface.
+ //
+ ntStatus = WdfDeviceMiniportCreate( WdfGetDriver(),
+ WDF_NO_OBJECT_ATTRIBUTES,
+ DeviceObject, // FDO
+ NULL, // Next device.
+ NULL, // PDO
+ &m_WdfDevice);
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("WdfDeviceMiniportCreate failed, 0x%x", ntStatus)),
+ Done);
+
+ // Initialize HW.
+ //
+ m_pHW = new (POOL_FLAG_NON_PAGED, SIMPLEAUDIOSAMPLE_POOLTAG) CSimpleAudioSampleHW;
+ if (!m_pHW)
+ {
+ DPF(D_TERSE, ("Insufficient memory for Simple Audio Sample HW"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ IF_FAILED_JUMP(ntStatus, Done);
+
+ m_pHW->MixerReset();
+
+ //
+ // Initialize SaveData class.
+ //
+ CSaveData::SetDeviceObject(DeviceObject); //device object is needed by CSaveData
+ ntStatus = CSaveData::InitializeWorkItems(DeviceObject);
+ IF_FAILED_JUMP(ntStatus, Done);
+Done:
+
+ return ntStatus;
+} // Init
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(void)
+CAdapterCommon::MixerReset
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Reset mixer registers from registry.
+
+Arguments:
+
+Return Value:
+
+ void
+
+--*/
+{
+ PAGED_CODE();
+
+ if (m_pHW)
+ {
+ m_pHW->MixerReset();
+ }
+} // MixerReset
+
+//=============================================================================
+/* Here are the definitions of the standard miniport events.
+
+Event type : eMINIPORT_IHV_DEFINED
+Parameter 1 : Defined and used by IHVs
+Parameter 2 : Defined and used by IHVs
+Parameter 3 : Defined and used by IHVs
+Parameter 4 :Defined and used by IHVs
+
+Event type: eMINIPORT_BUFFER_COMPLETE
+Parameter 1: Current linear buffer position
+Parameter 2: the previous WaveRtBufferWritePosition that the drive received
+Parameter 3: Data length completed
+Parameter 4:0
+
+Event type: eMINIPORT_PIN_STATE
+Parameter 1: Current linear buffer position
+Parameter 2: the previous WaveRtBufferWritePosition that the drive received
+Parameter 3: Pin State 0->KS_STOP, 1->KS_ACQUIRE, 2->KS_PAUSE, 3->KS_RUN
+Parameter 4:0
+
+Event type: eMINIPORT_GET_STREAM_POS
+Parameter 1: Current linear buffer position
+Parameter 2: the previous WaveRtBufferWritePosition that the drive received
+Parameter 3: 0
+Parameter 4:0
+
+
+Event type: eMINIPORT_SET_WAVERT_BUFFER_WRITE_POS
+Parameter 1: Current linear buffer position
+Parameter 2: the previous WaveRtBufferWritePosition that the drive received
+Parameter 3: the arget WaveRtBufferWritePosition received from portcls
+Parameter 4:0
+
+Event type: eMINIPORT_GET_PRESENTATION_POS
+Parameter 1: Current linear buffer position
+Parameter 2: the previous WaveRtBufferWritePosition that the drive received
+Parameter 3: Presentation position
+Parameter 4:0
+
+Event type: eMINIPORT_PROGRAM_DMA
+Parameter 1: Current linear buffer position
+Parameter 2: the previous WaveRtBufferWritePosition that the drive received
+Parameter 3: Starting WaveRt buffer offset
+Parameter 4: Data length
+
+Event type: eMINIPORT_GLITCH_REPORT
+Parameter 1: Current linear buffer position
+Parameter 2: the previous WaveRtBufferWritePosition that the drive received
+Parameter 3: major glitch code: 1:WaveRT buffer is underrun,
+ 2:decoder errors,
+ 3:receive the same wavert buffer two in a row in event driven mode
+Parameter 4: minor code for the glitch cause
+
+Event type: eMINIPORT_LAST_BUFFER_RENDERED
+Parameter 1: Current linear buffer position
+Parameter 2: the very last WaveRtBufferWritePosition that the driver received
+Parameter 3: 0
+Parameter 4: 0
+
+*/
+#pragma code_seg()
+STDMETHODIMP
+CAdapterCommon::WriteEtwEvent
+(
+ _In_ EPcMiniportEngineEvent miniportEventType,
+ _In_ ULONGLONG ullData1,
+ _In_ ULONGLONG ullData2,
+ _In_ ULONGLONG ullData3,
+ _In_ ULONGLONG ullData4
+)
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (m_pPortClsEtwHelper)
+ {
+ ntStatus = m_pPortClsEtwHelper->MiniportWriteEtwEvent( miniportEventType, ullData1, ullData2, ullData3, ullData4) ;
+ }
+ return ntStatus;
+} // WriteEtwEvent
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(void)
+CAdapterCommon::SetEtwHelper
+(
+ PPORTCLSETWHELPER _pPortClsEtwHelper
+)
+{
+ PAGED_CODE();
+
+ SAFE_RELEASE(m_pPortClsEtwHelper);
+
+ m_pPortClsEtwHelper = _pPortClsEtwHelper;
+
+ if (m_pPortClsEtwHelper)
+ {
+ m_pPortClsEtwHelper->AddRef();
+ }
+} // SetEtwHelper
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP
+CAdapterCommon::NonDelegatingQueryInterface
+(
+ _In_ REFIID Interface,
+ _COM_Outptr_ PVOID * Object
+)
+/*++
+
+Routine Description:
+
+ QueryInterface routine for AdapterCommon
+
+Arguments:
+
+ Interface -
+
+ Object -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(Object);
+
+ if (IsEqualGUIDAligned(Interface, IID_IUnknown))
+ {
+ *Object = PVOID(PUNKNOWN(PADAPTERCOMMON(this)));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IAdapterCommon))
+ {
+ *Object = PVOID(PADAPTERCOMMON(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IAdapterPowerManagement))
+ {
+ *Object = PVOID(PADAPTERPOWERMANAGEMENT(this));
+ }
+ else
+ {
+ *Object = NULL;
+ }
+
+ if (*Object)
+ {
+ PUNKNOWN(*Object)->AddRef();
+ return STATUS_SUCCESS;
+ }
+
+ return STATUS_INVALID_PARAMETER;
+} // NonDelegatingQueryInterface
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(void)
+CAdapterCommon::SetWaveServiceGroup
+(
+ _In_ PSERVICEGROUP ServiceGroup
+)
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::SetWaveServiceGroup]"));
+
+ SAFE_RELEASE(m_pServiceGroupWave);
+
+ m_pServiceGroupWave = ServiceGroup;
+
+ if (m_pServiceGroupWave)
+ {
+ m_pServiceGroupWave->AddRef();
+ }
+} // SetWaveServiceGroup
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(BOOL)
+CAdapterCommon::bDevSpecificRead()
+/*++
+
+Routine Description:
+
+ Fetch Device Specific information.
+
+Arguments:
+
+ N/A
+
+Return Value:
+
+ BOOL - Device Specific info
+
+--*/
+{
+ if (m_pHW)
+ {
+ return m_pHW->bGetDevSpecific();
+ }
+
+ return FALSE;
+} // bDevSpecificRead
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(void)
+CAdapterCommon::bDevSpecificWrite
+(
+ _In_ BOOL bDevSpecific
+)
+/*++
+
+Routine Description:
+
+ Store the new value in the Device Specific location.
+
+Arguments:
+
+ bDevSpecific - Value to store
+
+Return Value:
+
+ N/A.
+
+--*/
+{
+ if (m_pHW)
+ {
+ m_pHW->bSetDevSpecific(bDevSpecific);
+ }
+} // DevSpecificWrite
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(INT)
+CAdapterCommon::iDevSpecificRead()
+/*++
+
+Routine Description:
+
+ Fetch Device Specific information.
+
+Arguments:
+
+ N/A
+
+Return Value:
+
+ INT - Device Specific info
+
+--*/
+{
+ if (m_pHW)
+ {
+ return m_pHW->iGetDevSpecific();
+ }
+
+ return 0;
+} // iDevSpecificRead
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(void)
+CAdapterCommon::iDevSpecificWrite
+(
+ _In_ INT iDevSpecific
+)
+/*++
+
+Routine Description:
+
+ Store the new value in the Device Specific location.
+
+Arguments:
+
+ iDevSpecific - Value to store
+
+Return Value:
+
+ N/A.
+
+--*/
+{
+ if (m_pHW)
+ {
+ m_pHW->iSetDevSpecific(iDevSpecific);
+ }
+} // iDevSpecificWrite
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(UINT)
+CAdapterCommon::uiDevSpecificRead()
+/*++
+
+Routine Description:
+
+ Fetch Device Specific information.
+
+Arguments:
+
+ N/A
+
+Return Value:
+
+ UINT - Device Specific info
+
+--*/
+{
+ if (m_pHW)
+ {
+ return m_pHW->uiGetDevSpecific();
+ }
+
+ return 0;
+} // uiDevSpecificRead
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(void)
+CAdapterCommon::uiDevSpecificWrite
+(
+ _In_ UINT uiDevSpecific
+)
+/*++
+
+Routine Description:
+
+ Store the new value in the Device Specific location.
+
+Arguments:
+
+ uiDevSpecific - Value to store
+
+Return Value:
+
+ N/A.
+
+--*/
+{
+ if (m_pHW)
+ {
+ m_pHW->uiSetDevSpecific(uiDevSpecific);
+ }
+} // uiDevSpecificWrite
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(BOOL)
+CAdapterCommon::MixerMuteRead
+(
+ _In_ ULONG Index,
+ _In_ ULONG Channel
+)
+/*++
+
+Routine Description:
+
+ Store the new value in mixer register array.
+
+Arguments:
+
+ Index - node id
+
+Return Value:
+
+ BOOL - mixer mute setting for this node
+
+--*/
+{
+ if (m_pHW)
+ {
+ return m_pHW->GetMixerMute(Index, Channel);
+ }
+
+ return 0;
+} // MixerMuteRead
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(void)
+CAdapterCommon::MixerMuteWrite
+(
+ _In_ ULONG Index,
+ _In_ ULONG Channel,
+ _In_ BOOL Value
+)
+/*++
+
+Routine Description:
+
+ Store the new value in mixer register array.
+
+Arguments:
+
+ Index - node id
+
+ Value - new mute settings
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ if (m_pHW)
+ {
+ m_pHW->SetMixerMute(Index, Channel, Value);
+ }
+} // MixerMuteWrite
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(ULONG)
+CAdapterCommon::MixerMuxRead()
+/*++
+
+Routine Description:
+
+ Return the mux selection
+
+Arguments:
+
+ Index - node id
+
+ Value - new mute settings
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ if (m_pHW)
+ {
+ return m_pHW->GetMixerMux();
+ }
+
+ return 0;
+} // MixerMuxRead
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(void)
+CAdapterCommon::MixerMuxWrite
+(
+ _In_ ULONG Index
+)
+/*++
+
+Routine Description:
+
+ Store the new mux selection
+
+Arguments:
+
+ Index - node id
+
+ Value - new mute settings
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ if (m_pHW)
+ {
+ m_pHW->SetMixerMux(Index);
+ }
+} // MixerMuxWrite
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(LONG)
+CAdapterCommon::MixerVolumeRead
+(
+ _In_ ULONG Index,
+ _In_ ULONG Channel
+)
+/*++
+
+Routine Description:
+
+ Return the value in mixer register array.
+
+Arguments:
+
+ Index - node id
+
+ Channel = which channel
+
+Return Value:
+
+ Byte - mixer volume settings for this line
+
+--*/
+{
+ if (m_pHW)
+ {
+ return m_pHW->GetMixerVolume(Index, Channel);
+ }
+
+ return 0;
+} // MixerVolumeRead
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(void)
+CAdapterCommon::MixerVolumeWrite
+(
+ _In_ ULONG Index,
+ _In_ ULONG Channel,
+ _In_ LONG Value
+)
+/*++
+
+Routine Description:
+
+ Store the new value in mixer register array.
+
+Arguments:
+
+ Index - node id
+
+ Channel - which channel
+
+ Value - new volume level
+
+Return Value:
+
+ void
+
+--*/
+{
+ if (m_pHW)
+ {
+ m_pHW->SetMixerVolume(Index, Channel, Value);
+ }
+} // MixerVolumeWrite
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(LONG)
+CAdapterCommon::MixerPeakMeterRead
+(
+ _In_ ULONG Index,
+ _In_ ULONG Channel
+)
+/*++
+
+Routine Description:
+
+ Return the value in mixer register array.
+
+Arguments:
+
+ Index - node id
+
+ Channel = which channel
+
+Return Value:
+
+ Byte - mixer sample peak meter settings for this line
+
+--*/
+{
+ if (m_pHW)
+ {
+ return m_pHW->GetMixerPeakMeter(Index, Channel);
+ }
+
+ return 0;
+} // MixerVolumeRead
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(void)
+CAdapterCommon::PowerChangeState
+(
+ _In_ POWER_STATE NewState
+)
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ NewState - The requested, new power state for the device.
+
+Return Value:
+
+ void
+
+Note:
+ From MSDN:
+
+ To assist the driver, PortCls will pause any active audio streams prior to calling
+ this method to place the device in a sleep state. After calling this method, PortCls
+ will unpause active audio streams, to wake the device up. Miniports can opt for
+ additional notification by utilizing the IPowerNotify interface.
+
+ The miniport driver must perform the requested change to the device's power state
+ before it returns from the PowerChangeState call. If the miniport driver needs to
+ save or restore any device state before a power-state change, the miniport driver
+ should support the IPowerNotify interface, which allows it to receive advance warning
+ of any such change. Before returning from a successful PowerChangeState call, the
+ miniport driver should cache the new power state.
+
+ While the miniport driver is in one of the sleep states (any state other than
+ PowerDeviceD0), it must avoid writing to the hardware. The miniport driver must cache
+ any hardware accesses that need to be deferred until the device powers up again. If
+ the power state is changing from one of the sleep states to PowerDeviceD0, the
+ miniport driver should perform any deferred hardware accesses after it has powered up
+ the device. If the power state is changing from PowerDeviceD0 to a sleep state, the
+ miniport driver can perform any necessary hardware accesses during the PowerChangeState
+ call before it powers down the device.
+
+ While powered down, a miniport driver is never asked to create a miniport driver object
+ or stream object. PortCls always places the device in the PowerDeviceD0 state before
+ calling the miniport driver's NewStream method.
+
+--*/
+{
+ DPF_ENTER(("[CAdapterCommon::PowerChangeState]"));
+
+ // Notify all registered miniports of a power state change
+ PLIST_ENTRY le = NULL;
+ for (le = m_SubdeviceCache.Flink; le != &m_SubdeviceCache; le = le->Flink)
+ {
+ MINIPAIR_UNKNOWN *pRecord = CONTAINING_RECORD(le, MINIPAIR_UNKNOWN, ListEntry);
+
+ if (pRecord->PowerInterface)
+ {
+ pRecord->PowerInterface->PowerChangeState(NewState);
+ }
+ }
+
+ // is this actually a state change??
+ //
+ if (NewState.DeviceState != m_PowerState)
+ {
+ // switch on new state
+ //
+ switch (NewState.DeviceState)
+ {
+ case PowerDeviceD0:
+ case PowerDeviceD1:
+ case PowerDeviceD2:
+ case PowerDeviceD3:
+ m_PowerState = NewState.DeviceState;
+
+ DPF
+ (
+ D_VERBOSE,
+ ("Entering D%u", ULONG(m_PowerState) - ULONG(PowerDeviceD0))
+ );
+
+ break;
+
+ default:
+
+ DPF(D_VERBOSE, ("Unknown Device Power State"));
+ break;
+ }
+ }
+} // PowerStateChange
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::QueryDeviceCapabilities
+(
+ _Inout_updates_bytes_(sizeof(DEVICE_CAPABILITIES)) PDEVICE_CAPABILITIES PowerDeviceCaps
+)
+/*++
+
+Routine Description:
+
+ Called at startup to get the caps for the device. This structure provides
+ the system with the mappings between system power state and device power
+ state. This typically will not need modification by the driver.
+
+Arguments:
+
+ PowerDeviceCaps - The device's capabilities.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(PowerDeviceCaps);
+
+ DPF_ENTER(("[CAdapterCommon::QueryDeviceCapabilities]"));
+
+ return (STATUS_SUCCESS);
+} // QueryDeviceCapabilities
+
+//=============================================================================
+#pragma code_seg()
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::QueryPowerChangeState
+(
+ _In_ POWER_STATE NewStateQuery
+)
+/*++
+
+Routine Description:
+
+ Query to see if the device can change to this power state
+
+Arguments:
+
+ NewStateQuery - The requested, new power state for the device
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ DPF_ENTER(("[CAdapterCommon::QueryPowerChangeState]"));
+
+ // query each miniport for it's power state, we're finished if even one indicates
+ // it cannot go to this power state.
+ PLIST_ENTRY le = NULL;
+ for (le = m_SubdeviceCache.Flink; le != &m_SubdeviceCache && NT_SUCCESS(status); le = le->Flink)
+ {
+ MINIPAIR_UNKNOWN *pRecord = CONTAINING_RECORD(le, MINIPAIR_UNKNOWN, ListEntry);
+
+ if (pRecord->PowerInterface)
+ {
+ status = pRecord->PowerInterface->QueryPowerChangeState(NewStateQuery);
+ }
+ }
+
+ return status;
+} // QueryPowerChangeState
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CAdapterCommon::CreateAudioInterfaceWithProperties
+(
+ _In_ PCWSTR ReferenceString,
+ _In_opt_ PCWSTR TemplateReferenceString,
+ _In_ ULONG cPropertyCount,
+ _In_reads_opt_(cPropertyCount) const SIMPLEAUDIOSAMPLE_DEVPROPERTY *pProperties,
+ _Out_ _At_(AudioSymbolicLinkName->Buffer, __drv_allocatesMem(Mem)) PUNICODE_STRING AudioSymbolicLinkName
+)
+/*++
+
+Routine Description:
+
+Create the audio interface (in disabled mode).
+
+--*/
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::CreateAudioInterfaceWithProperties]"));
+
+ NTSTATUS ntStatus;
+ UNICODE_STRING referenceString;
+
+ RtlInitUnicodeString(&referenceString, ReferenceString);
+
+ //
+ // Reset output value.
+ //
+ RtlZeroMemory(AudioSymbolicLinkName, sizeof(UNICODE_STRING));
+
+ //
+ // Register an audio interface if not already present.
+ //
+ ntStatus = IoRegisterDeviceInterface(
+ GetPhysicalDeviceObject(),
+ &KSCATEGORY_AUDIO,
+ &referenceString,
+ AudioSymbolicLinkName);
+
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("CreateAudioInterfaceWithProperties: IoRegisterDeviceInterface(KSCATEGORY_AUDIO): failed, 0x%x", ntStatus)),
+ Done);
+
+ //
+ // Migrate optional device interface parameters from the template if it exists
+ // This is done first, so that any additional parameters in pProperties will override the defaults.
+ //
+ if (NULL != TemplateReferenceString)
+ {
+ ntStatus = MigrateDeviceInterfaceTemplateParameters(AudioSymbolicLinkName, TemplateReferenceString);
+
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("MigrateDeviceInterfaceTempalteParameters: MigrateDeviceInterfaceTemplateParameters(...): failed, 0x%x", ntStatus)),
+ Done);
+ }
+
+ //
+ // Set properties on the interface
+ //
+ ntStatus = SimpleAudioSampleIoSetDeviceInterfacePropertyDataMultiple(AudioSymbolicLinkName, cPropertyCount, pProperties);
+
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("CreateAudioInterfaceWithProperties: SimpleAudioSampleIoSetDeviceInterfacePropertyDataMultiple(...): failed, 0x%x", ntStatus)),
+ Done);
+
+ //
+ // All done.
+ //
+ ntStatus = STATUS_SUCCESS;
+
+Done:
+ if (!NT_SUCCESS(ntStatus))
+ {
+ RtlFreeUnicodeString(AudioSymbolicLinkName);
+ RtlZeroMemory(AudioSymbolicLinkName, sizeof(UNICODE_STRING));
+ }
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::InstallSubdevice
+(
+ _In_opt_ PIRP Irp,
+ _In_ PWSTR Name,
+ _In_opt_ PWSTR TemplateName,
+ _In_ REFGUID PortClassId,
+ _In_ REFGUID MiniportClassId,
+ _In_opt_ PFNCREATEMINIPORT MiniportCreate,
+ _In_ ULONG cPropertyCount,
+ _In_reads_opt_(cPropertyCount) const SIMPLEAUDIOSAMPLE_DEVPROPERTY * pProperties,
+ _In_opt_ PVOID DeviceContext,
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_opt_ PRESOURCELIST ResourceList,
+ _In_ REFGUID PortInterfaceId,
+ _Out_opt_ PUNKNOWN * OutPortInterface,
+ _Out_opt_ PUNKNOWN * OutPortUnknown,
+ _Out_opt_ PUNKNOWN * OutMiniportUnknown
+)
+{
+/*++
+
+Routine Description:
+
+ This function creates and registers a subdevice consisting of a port
+ driver, a minport driver and a set of resources bound together. It will
+ also optionally place a pointer to an interface on the port driver in a
+ specified location before initializing the port driver. This is done so
+ that a common ISR can have access to the port driver during
+ initialization, when the ISR might fire.
+
+Arguments:
+
+ Irp - pointer to the irp object.
+
+ Name - name of the miniport. Passes to PcRegisterSubDevice
+
+ PortClassId - port class id. Passed to PcNewPort.
+
+ MiniportClassId - miniport class id. Passed to PcNewMiniport.
+
+ MiniportCreate - pointer to a miniport creation function. If NULL,
+ PcNewMiniport is used.
+
+ DeviceContext - deviceType specific.
+
+ MiniportPair - endpoint configuration info.
+
+ ResourceList - pointer to the resource list.
+
+ PortInterfaceId - GUID that represents the port interface.
+
+ OutPortInterface - pointer to store the port interface
+
+ OutPortUnknown - pointer to store the unknown port interface.
+
+ OutMiniportUnknown - pointer to store the unknown miniport interface
+
+Return Value:
+
+ NT status code.
+
+--*/
+ PAGED_CODE();
+ DPF_ENTER(("[InstallSubDevice %S]", Name));
+
+ ASSERT(Name != NULL);
+ ASSERT(m_pDeviceObject != NULL);
+
+ NTSTATUS ntStatus;
+ PPORT port = NULL;
+ PUNKNOWN miniport = NULL;
+ PADAPTERCOMMON adapterCommon = NULL;
+ UNICODE_STRING symbolicLink = { 0 };
+
+ adapterCommon = PADAPTERCOMMON(this);
+
+ ntStatus = CreateAudioInterfaceWithProperties(Name, TemplateName, cPropertyCount, pProperties, &symbolicLink);
+ if (NT_SUCCESS(ntStatus))
+ {
+ // Currently have no use for the symbolic link
+ RtlFreeUnicodeString(&symbolicLink);
+
+ // Create the port driver object
+ //
+ ntStatus = PcNewPort(&port, PortClassId);
+ }
+
+ // Create the miniport object
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ if (MiniportCreate)
+ {
+ ntStatus =
+ MiniportCreate
+ (
+ &miniport,
+ MiniportClassId,
+ NULL,
+ POOL_FLAG_NON_PAGED,
+ adapterCommon,
+ DeviceContext,
+ MiniportPair
+ );
+ }
+ else
+ {
+ ntStatus =
+ PcNewMiniport
+ (
+ (PMINIPORT *) &miniport,
+ MiniportClassId
+ );
+ }
+ }
+
+ // Init the port driver and miniport in one go.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+#pragma warning(push)
+ // IPort::Init's annotation on ResourceList requires it to be non-NULL. However,
+ // for dynamic devices, we may no longer have the resource list and this should
+ // still succeed.
+ //
+#pragma warning(disable:6387)
+ ntStatus =
+ port->Init
+ (
+ m_pDeviceObject,
+ Irp,
+ miniport,
+ adapterCommon,
+ ResourceList
+ );
+#pragma warning (pop)
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ // Register the subdevice (port/miniport combination).
+ //
+ ntStatus =
+ PcRegisterSubdevice
+ (
+ m_pDeviceObject,
+ Name,
+ port
+ );
+ }
+ }
+
+ // Deposit the port interfaces if it's needed.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ if (OutPortUnknown)
+ {
+ ntStatus =
+ port->QueryInterface
+ (
+ IID_IUnknown,
+ (PVOID *)OutPortUnknown
+ );
+ }
+
+ if (OutPortInterface)
+ {
+ ntStatus =
+ port->QueryInterface
+ (
+ PortInterfaceId,
+ (PVOID *) OutPortInterface
+ );
+ }
+
+ if (OutMiniportUnknown)
+ {
+ ntStatus =
+ miniport->QueryInterface
+ (
+ IID_IUnknown,
+ (PVOID *)OutMiniportUnknown
+ );
+ }
+
+ }
+
+ if (port)
+ {
+ port->Release();
+ }
+
+ if (miniport)
+ {
+ miniport->Release();
+ }
+
+ return ntStatus;
+} // InstallSubDevice
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::UnregisterSubdevice
+(
+ _In_opt_ PUNKNOWN UnknownPort
+)
+/*++
+
+Routine Description:
+
+ Unregisters and releases the specified subdevice.
+
+Arguments:
+
+ UnknownPort - Wave or topology port interface.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::UnregisterSubdevice]"));
+
+ ASSERT(m_pDeviceObject != NULL);
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ PUNREGISTERSUBDEVICE unregisterSubdevice = NULL;
+
+ if (NULL == UnknownPort)
+ {
+ return ntStatus;
+ }
+
+ //
+ // Get the IUnregisterSubdevice interface.
+ //
+ ntStatus = UnknownPort->QueryInterface(
+ IID_IUnregisterSubdevice,
+ (PVOID *)&unregisterSubdevice);
+
+ //
+ // Unregister the port object.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = unregisterSubdevice->UnregisterSubdevice(
+ m_pDeviceObject,
+ UnknownPort);
+
+ //
+ // Release the IUnregisterSubdevice interface.
+ //
+ unregisterSubdevice->Release();
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::ConnectTopologies
+(
+ _In_ PUNKNOWN UnknownTopology,
+ _In_ PUNKNOWN UnknownWave,
+ _In_ PHYSICALCONNECTIONTABLE* PhysicalConnections,
+ _In_ ULONG PhysicalConnectionCount
+)
+/*++
+
+Routine Description:
+
+ Connects the bridge pins between the wave and mixer topologies.
+
+Arguments:
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::ConnectTopologies]"));
+
+ ASSERT(m_pDeviceObject != NULL);
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ //
+ // register wave <=> topology connections
+ // This will connect bridge pins of wave and topology
+ // miniports.
+ //
+ for (ULONG i = 0; i < PhysicalConnectionCount && NT_SUCCESS(ntStatus); i++)
+ {
+
+ switch(PhysicalConnections[i].eType)
+ {
+ case CONNECTIONTYPE_TOPOLOGY_OUTPUT:
+ ntStatus =
+ PcRegisterPhysicalConnection
+ (
+ m_pDeviceObject,
+ UnknownTopology,
+ PhysicalConnections[i].ulTopology,
+ UnknownWave,
+ PhysicalConnections[i].ulWave
+ );
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_TERSE, ("ConnectTopologies: PcRegisterPhysicalConnection(render) failed, 0x%x", ntStatus));
+ }
+ break;
+ case CONNECTIONTYPE_WAVE_OUTPUT:
+ ntStatus =
+ PcRegisterPhysicalConnection
+ (
+ m_pDeviceObject,
+ UnknownWave,
+ PhysicalConnections[i].ulWave,
+ UnknownTopology,
+ PhysicalConnections[i].ulTopology
+ );
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_TERSE, ("ConnectTopologies: PcRegisterPhysicalConnection(capture) failed, 0x%x", ntStatus));
+ }
+ break;
+ }
+ }
+
+ //
+ // Cleanup in case of error.
+ //
+ if (!NT_SUCCESS(ntStatus))
+ {
+ // disconnect all connections on error, ignore error code because not all
+ // connections may have been made
+ DisconnectTopologies(UnknownTopology, UnknownWave, PhysicalConnections, PhysicalConnectionCount);
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::DisconnectTopologies
+(
+ _In_ PUNKNOWN UnknownTopology,
+ _In_ PUNKNOWN UnknownWave,
+ _In_ PHYSICALCONNECTIONTABLE* PhysicalConnections,
+ _In_ ULONG PhysicalConnectionCount
+)
+/*++
+
+Routine Description:
+
+ Disconnects the bridge pins between the wave and mixer topologies.
+
+Arguments:
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::DisconnectTopologies]"));
+
+ ASSERT(m_pDeviceObject != NULL);
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ NTSTATUS ntStatus2 = STATUS_SUCCESS;
+ PUNREGISTERPHYSICALCONNECTION unregisterPhysicalConnection = NULL;
+
+ //
+ // Get the IUnregisterPhysicalConnection interface
+ //
+ ntStatus = UnknownTopology->QueryInterface(
+ IID_IUnregisterPhysicalConnection,
+ (PVOID *)&unregisterPhysicalConnection);
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ for (ULONG i = 0; i < PhysicalConnectionCount; i++)
+ {
+ switch(PhysicalConnections[i].eType)
+ {
+ case CONNECTIONTYPE_TOPOLOGY_OUTPUT:
+ ntStatus =
+ unregisterPhysicalConnection->UnregisterPhysicalConnection(
+ m_pDeviceObject,
+ UnknownTopology,
+ PhysicalConnections[i].ulTopology,
+ UnknownWave,
+ PhysicalConnections[i].ulWave
+ );
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_TERSE, ("DisconnectTopologies: UnregisterPhysicalConnection(render) failed, 0x%x", ntStatus));
+ }
+ break;
+ case CONNECTIONTYPE_WAVE_OUTPUT:
+ ntStatus =
+ unregisterPhysicalConnection->UnregisterPhysicalConnection(
+ m_pDeviceObject,
+ UnknownWave,
+ PhysicalConnections[i].ulWave,
+ UnknownTopology,
+ PhysicalConnections[i].ulTopology
+ );
+ if (!NT_SUCCESS(ntStatus2))
+ {
+ DPF(D_TERSE, ("DisconnectTopologies: UnregisterPhysicalConnection(capture) failed, 0x%x", ntStatus2));
+ }
+ break;
+ }
+
+ // cache and return the first error encountered, as it's likely the most relevent
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = ntStatus2;
+ }
+ }
+ }
+
+ //
+ // Release the IUnregisterPhysicalConnection interface.
+ //
+ SAFE_RELEASE(unregisterPhysicalConnection);
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CAdapterCommon::GetCachedSubdevice
+(
+ _In_ PWSTR Name,
+ _Out_opt_ PUNKNOWN *OutUnknownPort,
+ _Out_opt_ PUNKNOWN *OutUnknownMiniport
+)
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::GetCachedSubdevice]"));
+
+ // search list, return interface to device if found, fail if not found
+ PLIST_ENTRY le = NULL;
+ BOOL bFound = FALSE;
+
+ for (le = m_SubdeviceCache.Flink; le != &m_SubdeviceCache && !bFound; le = le->Flink)
+ {
+ MINIPAIR_UNKNOWN *pRecord = CONTAINING_RECORD(le, MINIPAIR_UNKNOWN, ListEntry);
+
+ if (0 == wcscmp(Name, pRecord->Name))
+ {
+ if (OutUnknownPort)
+ {
+ *OutUnknownPort = pRecord->PortInterface;
+ (*OutUnknownPort)->AddRef();
+ }
+
+ if (OutUnknownMiniport)
+ {
+ *OutUnknownMiniport = pRecord->MiniportInterface;
+ (*OutUnknownMiniport)->AddRef();
+ }
+
+ bFound = TRUE;
+ }
+ }
+
+ return bFound?STATUS_SUCCESS:STATUS_OBJECT_NAME_NOT_FOUND;
+}
+
+
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CAdapterCommon::CacheSubdevice
+(
+ _In_ PWSTR Name,
+ _In_ PUNKNOWN UnknownPort,
+ _In_ PUNKNOWN UnknownMiniport
+)
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::CacheSubdevice]"));
+
+ // add the item with this name/interface to the list
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ MINIPAIR_UNKNOWN *pNewSubdevice = NULL;
+
+ pNewSubdevice = new(POOL_FLAG_NON_PAGED, MINADAPTER_POOLTAG) MINIPAIR_UNKNOWN;
+
+ if (!pNewSubdevice)
+ {
+ DPF(D_TERSE, ("Insufficient memory to cache subdevice"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ memset(pNewSubdevice, 0, sizeof(MINIPAIR_UNKNOWN));
+
+ ntStatus = RtlStringCchCopyW(pNewSubdevice->Name, SIZEOF_ARRAY(pNewSubdevice->Name), Name);
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ pNewSubdevice->PortInterface = UnknownPort;
+ pNewSubdevice->PortInterface->AddRef();
+
+ pNewSubdevice->MiniportInterface = UnknownMiniport;
+ pNewSubdevice->MiniportInterface->AddRef();
+
+ // cache the IAdapterPowerManagement interface (if available) from the filter. Some endpoints,
+ // like FM and cellular, have their own power requirements that we must track. If this fails,
+ // it just means this filter doesn't do power management.
+ UnknownMiniport->QueryInterface(IID_IAdapterPowerManagement, (PVOID *)&(pNewSubdevice->PowerInterface));
+
+ InsertTailList(&m_SubdeviceCache, &pNewSubdevice->ListEntry);
+ }
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ if (pNewSubdevice)
+ {
+ delete pNewSubdevice;
+ }
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CAdapterCommon::RemoveCachedSubdevice
+(
+ _In_ PWSTR Name
+)
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::RemoveCachedSubdevice]"));
+
+ // search list, remove the entry from the list
+
+ PLIST_ENTRY le = NULL;
+ BOOL bRemoved = FALSE;
+
+ for (le = m_SubdeviceCache.Flink; le != &m_SubdeviceCache && !bRemoved; le = le->Flink)
+ {
+ MINIPAIR_UNKNOWN *pRecord = CONTAINING_RECORD(le, MINIPAIR_UNKNOWN, ListEntry);
+
+ if (0 == wcscmp(Name, pRecord->Name))
+ {
+ SAFE_RELEASE(pRecord->PortInterface);
+ SAFE_RELEASE(pRecord->MiniportInterface);
+ SAFE_RELEASE(pRecord->PowerInterface);
+ memset(pRecord->Name, 0, sizeof(pRecord->Name));
+ RemoveEntryList(le);
+ bRemoved = TRUE;
+ delete pRecord;
+ break;
+ }
+ }
+
+ return bRemoved?STATUS_SUCCESS:STATUS_OBJECT_NAME_NOT_FOUND;
+}
+
+#pragma code_seg("PAGE")
+VOID
+CAdapterCommon::EmptySubdeviceCache()
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::EmptySubdeviceCache]"));
+
+ while (!IsListEmpty(&m_SubdeviceCache))
+ {
+ PLIST_ENTRY le = RemoveHeadList(&m_SubdeviceCache);
+ MINIPAIR_UNKNOWN *pRecord = CONTAINING_RECORD(le, MINIPAIR_UNKNOWN, ListEntry);
+
+ SAFE_RELEASE(pRecord->PortInterface);
+ SAFE_RELEASE(pRecord->MiniportInterface);
+ SAFE_RELEASE(pRecord->PowerInterface);
+ memset(pRecord->Name, 0, sizeof(pRecord->Name));
+
+ delete pRecord;
+ }
+}
+
+#pragma code_seg("PAGE")
+VOID
+CAdapterCommon::Cleanup()
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::Cleanup]"));
+ EmptySubdeviceCache();
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::InstallEndpointFilters
+(
+ _In_opt_ PIRP Irp,
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_opt_ PVOID DeviceContext,
+ _Out_opt_ PUNKNOWN * UnknownTopology,
+ _Out_opt_ PUNKNOWN * UnknownWave,
+ _Out_opt_ PUNKNOWN * UnknownMiniportTopology,
+ _Out_opt_ PUNKNOWN * UnknownMiniportWave
+)
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::InstallEndpointFilters]"));
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ PUNKNOWN unknownTopology = NULL;
+ PUNKNOWN unknownWave = NULL;
+ BOOL bTopologyCreated = FALSE;
+ BOOL bWaveCreated = FALSE;
+ PUNKNOWN unknownMiniTopo = NULL;
+ PUNKNOWN unknownMiniWave = NULL;
+
+ // Initialize output optional parameters if needed
+ if (UnknownTopology)
+ {
+ *UnknownTopology = NULL;
+ }
+
+ if (UnknownWave)
+ {
+ *UnknownWave = NULL;
+ }
+
+ if (UnknownMiniportTopology)
+ {
+ *UnknownMiniportTopology = NULL;
+ }
+
+ if (UnknownMiniportWave)
+ {
+ *UnknownMiniportWave = NULL;
+ }
+
+ ntStatus = GetCachedSubdevice(MiniportPair->TopoName, &unknownTopology, &unknownMiniTopo);
+ if (!NT_SUCCESS(ntStatus) || NULL == unknownTopology || NULL == unknownMiniTopo)
+ {
+ bTopologyCreated = TRUE;
+
+ // Install Simple Audio Sample topology miniport for the render endpoint.
+ //
+ ntStatus = InstallSubdevice(Irp,
+ MiniportPair->TopoName, // make sure this name matches with SIMPLEAUDIOSAMPLE.<TopoName>.szPname in the inf's [Strings] section
+ MiniportPair->TemplateTopoName,
+ CLSID_PortTopology,
+ CLSID_PortTopology,
+ MiniportPair->TopoCreateCallback,
+ MiniportPair->TopoInterfacePropertyCount,
+ MiniportPair->TopoInterfaceProperties,
+ DeviceContext,
+ MiniportPair,
+ NULL,
+ IID_IPortTopology,
+ NULL,
+ &unknownTopology,
+ &unknownMiniTopo
+ );
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = CacheSubdevice(MiniportPair->TopoName, unknownTopology, unknownMiniTopo);
+ }
+ }
+
+ ntStatus = GetCachedSubdevice(MiniportPair->WaveName, &unknownWave, &unknownMiniWave);
+ if (!NT_SUCCESS(ntStatus) || NULL == unknownWave || NULL == unknownMiniWave)
+ {
+ bWaveCreated = TRUE;
+
+ // Install Simple Audio Sample wave miniport for the render endpoint.
+ //
+ ntStatus = InstallSubdevice(Irp,
+ MiniportPair->WaveName, // make sure this name matches with SIMPLEAUDIOSAMPLE.<WaveName>.szPname in the inf's [Strings] section
+ MiniportPair->TemplateWaveName,
+ CLSID_PortWaveRT,
+ CLSID_PortWaveRT,
+ MiniportPair->WaveCreateCallback,
+ MiniportPair->WaveInterfacePropertyCount,
+ MiniportPair->WaveInterfaceProperties,
+ DeviceContext,
+ MiniportPair,
+ NULL,
+ IID_IPortWaveRT,
+ NULL,
+ &unknownWave,
+ &unknownMiniWave
+ );
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = CacheSubdevice(MiniportPair->WaveName, unknownWave, unknownMiniWave);
+ }
+ }
+
+ if (unknownTopology && unknownWave)
+ {
+ //
+ // register wave <=> topology connections
+ // This will connect bridge pins of wave and topology
+ // miniports.
+ //
+ ntStatus = ConnectTopologies(
+ unknownTopology,
+ unknownWave,
+ MiniportPair->PhysicalConnections,
+ MiniportPair->PhysicalConnectionCount);
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ //
+ // Set output parameters.
+ //
+ if (UnknownTopology != NULL && unknownTopology != NULL)
+ {
+ unknownTopology->AddRef();
+ *UnknownTopology = unknownTopology;
+ }
+
+ if (UnknownWave != NULL && unknownWave != NULL)
+ {
+ unknownWave->AddRef();
+ *UnknownWave = unknownWave;
+ }
+ if (UnknownMiniportTopology != NULL && unknownMiniTopo != NULL)
+ {
+ unknownMiniTopo->AddRef();
+ *UnknownMiniportTopology = unknownMiniTopo;
+ }
+
+ if (UnknownMiniportWave != NULL && unknownMiniWave != NULL)
+ {
+ unknownMiniWave->AddRef();
+ *UnknownMiniportWave = unknownMiniWave;
+ }
+
+ }
+ else
+ {
+ if (bTopologyCreated && unknownTopology != NULL)
+ {
+ UnregisterSubdevice(unknownTopology);
+ RemoveCachedSubdevice(MiniportPair->TopoName);
+ }
+
+ if (bWaveCreated && unknownWave != NULL)
+ {
+ UnregisterSubdevice(unknownWave);
+ RemoveCachedSubdevice(MiniportPair->WaveName);
+ }
+ }
+
+ SAFE_RELEASE(unknownMiniTopo);
+ SAFE_RELEASE(unknownTopology);
+ SAFE_RELEASE(unknownMiniWave);
+ SAFE_RELEASE(unknownWave);
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::RemoveEndpointFilters
+(
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_opt_ PUNKNOWN UnknownTopology,
+ _In_opt_ PUNKNOWN UnknownWave
+)
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::RemoveEndpointFilters]"));
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (UnknownTopology != NULL && UnknownWave != NULL)
+ {
+ ntStatus = DisconnectTopologies(
+ UnknownTopology,
+ UnknownWave,
+ MiniportPair->PhysicalConnections,
+ MiniportPair->PhysicalConnectionCount);
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_VERBOSE, ("RemoveEndpointFilters: DisconnectTopologies failed: 0x%x", ntStatus));
+ }
+ }
+
+
+ RemoveCachedSubdevice(MiniportPair->WaveName);
+
+ ntStatus = UnregisterSubdevice(UnknownWave);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_VERBOSE, ("RemoveEndpointFilters: UnregisterSubdevice(wave) failed: 0x%x", ntStatus));
+ }
+
+ RemoveCachedSubdevice(MiniportPair->TopoName);
+
+ ntStatus = UnregisterSubdevice(UnknownTopology);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_VERBOSE, ("RemoveEndpointFilters: UnregisterSubdevice(topology) failed: 0x%x", ntStatus));
+ }
+
+ //
+ // All Done.
+ //
+ ntStatus = STATUS_SUCCESS;
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::GetFilters
+(
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _Out_opt_ PUNKNOWN * UnknownTopologyPort,
+ _Out_opt_ PUNKNOWN * UnknownTopologyMiniport,
+ _Out_opt_ PUNKNOWN * UnknownWavePort,
+ _Out_opt_ PUNKNOWN * UnknownWaveMiniport
+)
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::GetFilters]"));
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ PUNKNOWN unknownTopologyPort = NULL;
+ PUNKNOWN unknownTopologyMiniport = NULL;
+ PUNKNOWN unknownWavePort = NULL;
+ PUNKNOWN unknownWaveMiniport = NULL;
+
+ // if the client requested the topology filter, find it and return it
+ if (UnknownTopologyPort != NULL || UnknownTopologyMiniport != NULL)
+ {
+ ntStatus = GetCachedSubdevice(MiniportPair->TopoName, &unknownTopologyPort, &unknownTopologyMiniport);
+ if (NT_SUCCESS(ntStatus))
+ {
+ if (UnknownTopologyPort)
+ {
+ *UnknownTopologyPort = unknownTopologyPort;
+ }
+
+ if (UnknownTopologyMiniport)
+ {
+ *UnknownTopologyMiniport = unknownTopologyMiniport;
+ }
+ }
+ }
+
+ // if the client requested the wave filter, find it and return it
+ if (NT_SUCCESS(ntStatus) && (UnknownWavePort != NULL || UnknownWaveMiniport != NULL))
+ {
+ ntStatus = GetCachedSubdevice(MiniportPair->WaveName, &unknownWavePort, &unknownWaveMiniport);
+ if (NT_SUCCESS(ntStatus))
+ {
+ if (UnknownWavePort)
+ {
+ *UnknownWavePort = unknownWavePort;
+ }
+
+ if (UnknownWaveMiniport)
+ {
+ *UnknownWaveMiniport = unknownWaveMiniport;
+ }
+ }
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CAdapterCommon::SetIdlePowerManagement
+(
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_ BOOL bEnabled
+)
+{
+ PAGED_CODE();
+ DPF_ENTER(("[CAdapterCommon::SetIdlePowerManagement]"));
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ IUnknown *pUnknown = NULL;
+ PPORTCLSPOWER pPortClsPower = NULL;
+ // refcounting disable requests. Each miniport is responsible for calling this in pairs,
+ // disable on the first request to disable, enable on the last request to enable.
+
+ // make sure that we always call SetIdlePowerManagment using the IPortClsPower
+ // from the requesting port, so we don't cache a reference to a port
+ // indefinitely, preventing it from ever unloading.
+ ntStatus = GetFilters(MiniportPair, NULL, NULL, &pUnknown, NULL);
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus =
+ pUnknown->QueryInterface
+ (
+ IID_IPortClsPower,
+ (PVOID*) &pPortClsPower
+ );
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ if (bEnabled)
+ {
+ m_dwIdleRequests--;
+
+ if (0 == m_dwIdleRequests)
+ {
+ pPortClsPower->SetIdlePowerManagement(m_pDeviceObject, TRUE);
+ }
+ }
+ else
+ {
+ if (0 == m_dwIdleRequests)
+ {
+ pPortClsPower->SetIdlePowerManagement(m_pDeviceObject, FALSE);
+ }
+
+ m_dwIdleRequests++;
+ }
+ }
+
+ SAFE_RELEASE(pUnknown);
+ SAFE_RELEASE(pPortClsPower);
+
+ return ntStatus;
+}
+
+#pragma code_seg("PAGE")
+NTSTATUS
+CopyRegistryValues(HANDLE _hSourceKey, HANDLE _hDestinationKey)
+/*++
+
+Routine Description:
+
+ This method copies the registry values in _hSourceKey to _hDestinationKey.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ PKEY_VALUE_FULL_INFORMATION kvFullInfo = NULL;
+ ULONG ulFullInfoLength = 0;
+ ULONG ulFullInfoResultLength = 0;
+ PWSTR pwstrKeyValueName = NULL;
+ UNICODE_STRING strKeyValueName;
+ PAGED_CODE();
+ // Allocate the KEY_VALUE_FULL_INFORMATION structure
+ ulFullInfoLength = sizeof(KEY_VALUE_FULL_INFORMATION) + MAX_DEVICE_REG_KEY_LENGTH;
+ kvFullInfo = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, ulFullInfoLength, MINADAPTER_POOLTAG);
+ IF_TRUE_ACTION_JUMP(kvFullInfo == NULL, ntStatus = STATUS_INSUFFICIENT_RESOURCES, Exit);
+
+ // Iterate over each value and copy it to the destination
+ for (UINT i = 0; NT_SUCCESS(ntStatus); i++)
+ {
+ // Enumerate the next value
+ ntStatus = ZwEnumerateValueKey(_hSourceKey, i, KeyValueFullInformation, kvFullInfo, ulFullInfoLength, &ulFullInfoResultLength);
+
+ // Jump out of this loop if there are no more values
+ IF_TRUE_ACTION_JUMP(ntStatus == STATUS_NO_MORE_ENTRIES, ntStatus = STATUS_SUCCESS, Exit);
+
+ // Handle incorrect buffer size
+ if (ntStatus == STATUS_BUFFER_TOO_SMALL || ntStatus == STATUS_BUFFER_OVERFLOW)
+ {
+ // Free and re-allocate the KEY_VALUE_FULL_INFORMATION structure with the correct size
+ ExFreePoolWithTag(kvFullInfo, MINADAPTER_POOLTAG);
+
+ ulFullInfoLength = ulFullInfoResultLength;
+
+ kvFullInfo = (PKEY_VALUE_FULL_INFORMATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, ulFullInfoLength, MINADAPTER_POOLTAG);
+ IF_TRUE_ACTION_JUMP(kvFullInfo == NULL, ntStatus = STATUS_INSUFFICIENT_RESOURCES, loop_exit);
+
+ // Try to enumerate the current value again
+ ntStatus = ZwEnumerateValueKey(_hSourceKey, i, KeyValueFullInformation, kvFullInfo, ulFullInfoLength, &ulFullInfoResultLength);
+
+ // Jump out of this loop if there are no more values
+ IF_TRUE_ACTION_JUMP(ntStatus == STATUS_NO_MORE_ENTRIES, ntStatus = STATUS_SUCCESS, Exit);
+ IF_FAILED_JUMP(ntStatus, loop_exit);
+ }
+ else
+ {
+ IF_FAILED_JUMP(ntStatus, loop_exit);
+ }
+
+ // Allocate the key value name string
+ pwstrKeyValueName = (PWSTR)ExAllocatePool2(POOL_FLAG_NON_PAGED, kvFullInfo->NameLength + sizeof(WCHAR)*2, MINADAPTER_POOLTAG);
+ IF_TRUE_ACTION_JUMP(kvFullInfo == NULL, ntStatus = STATUS_INSUFFICIENT_RESOURCES, loop_exit);
+
+ // Copy the key value name from the full information struct
+ RtlStringCbCopyNW(pwstrKeyValueName, kvFullInfo->NameLength + sizeof(WCHAR)*2, kvFullInfo->Name, kvFullInfo->NameLength);
+
+ // Make sure the string is null terminated
+ pwstrKeyValueName[(kvFullInfo->NameLength) / sizeof(WCHAR)] = 0;
+
+ // Copy the key value name string to a UNICODE string
+ RtlInitUnicodeString(&strKeyValueName, pwstrKeyValueName);
+
+ // Write the key value from the source into the destination
+ ntStatus = ZwSetValueKey(_hDestinationKey, &strKeyValueName, 0, kvFullInfo->Type, (PVOID)((PUCHAR)kvFullInfo + kvFullInfo->DataOffset), kvFullInfo->DataLength);
+ IF_FAILED_JUMP(ntStatus, loop_exit);
+
+ loop_exit:
+ // Free the key value name string
+ if (pwstrKeyValueName)
+ {
+ ExFreePoolWithTag(pwstrKeyValueName, MINADAPTER_POOLTAG);
+ }
+
+ // Bail if anything failed
+ IF_FAILED_JUMP(ntStatus, Exit);
+ }
+
+Exit:
+ // Free the KEY_VALUE_FULL_INFORMATION structure
+ if (kvFullInfo)
+ {
+ ExFreePoolWithTag(kvFullInfo, MINADAPTER_POOLTAG);
+ }
+
+ return ntStatus;
+}
+
+NTSTATUS
+CopyRegistryKey(HANDLE _hSourceKey, HANDLE _hDestinationKey, BOOL _bOverwrite = FALSE)
+/*++
+
+Routine Description:
+
+ This method recursively copies the registry values in _hSourceKey to _hDestinationKey.
+ Set _bOverwrite to indicate whether the first level values are copied or not.
+ Normal use is to set false for the initial call, and then all sub paths will be copied.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
+ PKEY_BASIC_INFORMATION kBasicInfo = NULL;
+ ULONG ulBasicInfoLength = 0;
+ ULONG ulBasicInfoResultLength = 0;
+ ULONG ulDisposition = 0;
+ PWSTR pwstrKeyName = NULL;
+ UNICODE_STRING strKeyName;
+ OBJECT_ATTRIBUTES hCurrentSourceKeyAttributes;
+ OBJECT_ATTRIBUTES hNewDestinationKeyAttributes;
+ HANDLE hCurrentSourceKey = NULL;
+ HANDLE hNewDestinationKey = NULL;
+ PAGED_CODE();
+ // Validate parameters
+ IF_TRUE_ACTION_JUMP(_hSourceKey == nullptr, ntStatus = STATUS_INVALID_PARAMETER, Exit);
+ IF_TRUE_ACTION_JUMP(_hDestinationKey == nullptr, ntStatus = STATUS_INVALID_PARAMETER, Exit);
+
+ // Allocate the KEY_BASIC_INFORMATION structure
+ ulBasicInfoLength = sizeof(KEY_BASIC_INFORMATION) + MAX_DEVICE_REG_KEY_LENGTH;
+ kBasicInfo = (PKEY_BASIC_INFORMATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, ulBasicInfoLength, MINADAPTER_POOLTAG);
+ IF_TRUE_ACTION_JUMP(kBasicInfo == NULL, ntStatus = STATUS_INSUFFICIENT_RESOURCES, Exit);
+
+ ntStatus = STATUS_SUCCESS;
+ // Iterate over each key and copy it
+ for (UINT i = 0; NT_SUCCESS(ntStatus); i++)
+ {
+ // Enumerate the next key
+ ntStatus = ZwEnumerateKey(_hSourceKey, i, KeyBasicInformation, kBasicInfo, ulBasicInfoLength, &ulBasicInfoResultLength);
+
+ // Jump out of this loop if there are no more keys
+ IF_TRUE_ACTION_JUMP(ntStatus == STATUS_NO_MORE_ENTRIES, ntStatus = STATUS_SUCCESS, copy_values);
+
+ // Handle incorrect buffer size
+ if (ntStatus == STATUS_BUFFER_TOO_SMALL || ntStatus == STATUS_BUFFER_OVERFLOW)
+ {
+ // Free and re-allocate the KEY_BASIC_INFORMATION structure with the correct size.
+ ExFreePoolWithTag(kBasicInfo, MINADAPTER_POOLTAG);
+ ulBasicInfoLength = ulBasicInfoResultLength;
+ kBasicInfo = (PKEY_BASIC_INFORMATION)ExAllocatePool2(POOL_FLAG_NON_PAGED, ulBasicInfoLength, MINADAPTER_POOLTAG);
+ IF_TRUE_ACTION_JUMP(kBasicInfo == NULL, ntStatus = STATUS_INSUFFICIENT_RESOURCES, loop_exit);
+
+ // Try to enumerate the current key again.
+ ntStatus = ZwEnumerateKey(_hSourceKey, i, KeyBasicInformation, kBasicInfo, ulBasicInfoLength, &ulBasicInfoResultLength);
+
+ // Jump out of this loop if there are no more keys
+ IF_TRUE_ACTION_JUMP(ntStatus == STATUS_NO_MORE_ENTRIES, ntStatus = STATUS_SUCCESS, copy_values);
+ IF_FAILED_JUMP(ntStatus, loop_exit);
+ }
+ else
+ {
+ IF_FAILED_JUMP(ntStatus, loop_exit);
+ }
+
+ // Allocate the key name string
+ pwstrKeyName = (PWSTR)ExAllocatePool2(POOL_FLAG_NON_PAGED, kBasicInfo->NameLength + sizeof(WCHAR), MINADAPTER_POOLTAG);
+ IF_TRUE_ACTION_JUMP(kBasicInfo == NULL, ntStatus = STATUS_INSUFFICIENT_RESOURCES, loop_exit);
+
+ // Copy the key name from the basic information struct
+ RtlStringCbCopyNW(pwstrKeyName, kBasicInfo->NameLength + sizeof(WCHAR), kBasicInfo->Name, kBasicInfo->NameLength);
+
+ // Make sure the string is null terminated
+ pwstrKeyName[(kBasicInfo->NameLength) / sizeof(WCHAR)] = 0;
+
+ // Copy the key name string to a UNICODE string
+ RtlInitUnicodeString(&strKeyName, pwstrKeyName);
+
+ // Initialize attributes to open the currently enumerated source key
+ InitializeObjectAttributes(&hCurrentSourceKeyAttributes, &strKeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, _hSourceKey, NULL);
+
+ // Open the currently enumerated source key
+ ntStatus = ZwOpenKey(&hCurrentSourceKey, KEY_READ, &hCurrentSourceKeyAttributes);
+ IF_FAILED_ACTION_JUMP(ntStatus, ZwClose(hCurrentSourceKey), loop_exit);
+
+ // Initialize attributes to create the new destination key
+ InitializeObjectAttributes(&hNewDestinationKeyAttributes, &strKeyName, OBJ_KERNEL_HANDLE, _hDestinationKey, NULL);
+
+ // Create the key at the destination
+ ntStatus = ZwCreateKey(&hNewDestinationKey, KEY_WRITE, &hNewDestinationKeyAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, &ulDisposition);
+ IF_FAILED_ACTION_JUMP(ntStatus, ZwClose(hCurrentSourceKey), loop_exit);
+
+ // Now copy the contents of the currently enumerated key to the destination
+ ntStatus = CopyRegistryKey(hCurrentSourceKey, hNewDestinationKey, TRUE);
+ IF_FAILED_JUMP(ntStatus, loop_exit);
+
+ loop_exit:
+ // Free the key name string
+ if (pwstrKeyName)
+ {
+ ExFreePoolWithTag(pwstrKeyName, MINADAPTER_POOLTAG);
+ }
+
+ // Close the current source key
+ if (hCurrentSourceKey)
+ {
+ ZwClose(hCurrentSourceKey);
+ }
+
+ // Close the new destination key
+ if (hNewDestinationKey)
+ {
+ ZwClose(hNewDestinationKey);
+ }
+
+ // Bail if anything failed
+ IF_FAILED_JUMP(ntStatus, Exit);
+ }
+
+copy_values:
+ // Copy the values
+ if (_bOverwrite)
+ {
+ ntStatus = CopyRegistryValues(_hSourceKey, _hDestinationKey);
+ IF_FAILED_JUMP(ntStatus, Exit);
+ }
+
+Exit:
+ // Free the basic information structure
+ if (kBasicInfo)
+ {
+ ExFreePoolWithTag(kBasicInfo, MINADAPTER_POOLTAG);
+ }
+ return ntStatus;
+}
+
+
+NTSTATUS CAdapterCommon::MigrateDeviceInterfaceTemplateParameters
+(
+ _In_ PUNICODE_STRING SymbolicLinkName,
+ _In_opt_ PCWSTR TemplateReferenceString
+)
+/*++
+
+Routine Description:
+
+ This method copies all of the properties from the template interface,
+ which is specified in the inf, to the actual interface being used which
+ may be dynamically generated at run time. This allows for a driver
+ to reuse a single inf entry for multiple audio endpoints. The primary
+ purpose for this is to allow for sideband audio endpoints to dynamically
+ generate the reference string at run time, tied to the peripheral connected,
+ while still having a simple static inf entry for setting up apo's or other
+ parameters.
+
+ For example, if you have an interface in your inf defined with reference string
+ "SpeakerWave". At runtime you could generate "SpeakerWave-1234ABCDE", and specify
+ "SpeakerWave" as the template name. When "SpeakerWave-1234ABCDE" is installed
+ we will copy all of the parameters that were specified in the inf for "SpeakerWave"
+ over to "SpeakerWave-1234ABCDE". You simply need to specify "SpeakerWave" as the
+ "TemplateName" in the ENDPOINT_MINIPAIRS.
+
+ By default, the first level of registry keys are not copied. Only the 2nd level and
+ deeper are copied. This way the friendly name and other PNP properties will not
+ be modified, but the EP and FX properties will be copied.
+
+Return Value:
+
+ NT status code.
+
+--*/
+
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ HANDLE hDeviceInterfaceParametersKey(NULL);
+ HANDLE hTemplateDeviceInterfaceParametersKey(NULL);
+ UNICODE_STRING TemplateSymbolicLinkName;
+ UNICODE_STRING referenceString;
+
+ RtlInitUnicodeString(&TemplateSymbolicLinkName, NULL);
+ RtlInitUnicodeString(&referenceString, TemplateReferenceString);
+
+ //
+ // Register an audio interface if not already present for the template interface, so we can access
+ // the registry path. If it's already registered, this simply returns the symbolic link name.
+ // No need to unregister it (there is no mechanism to), and we'll never make it active.
+ //
+ ntStatus = IoRegisterDeviceInterface(
+ GetPhysicalDeviceObject(),
+ &KSCATEGORY_AUDIO,
+ &referenceString,
+ &TemplateSymbolicLinkName);
+
+ // Open the template device interface's registry key path
+ ntStatus = IoOpenDeviceInterfaceRegistryKey(&TemplateSymbolicLinkName, GENERIC_READ, &hTemplateDeviceInterfaceParametersKey);
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+ // Open the new device interface's registry key path that we plan to activate
+ ntStatus = IoOpenDeviceInterfaceRegistryKey(SymbolicLinkName, GENERIC_WRITE, &hDeviceInterfaceParametersKey);
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+ // Copy the template device parameters key to the device interface key
+ ntStatus = CopyRegistryKey(hTemplateDeviceInterfaceParametersKey, hDeviceInterfaceParametersKey);
+ IF_FAILED_JUMP(ntStatus, Exit);
+
+Exit:
+ RtlFreeUnicodeString(&TemplateSymbolicLinkName);
+
+ if (hTemplateDeviceInterfaceParametersKey)
+ {
+ ZwClose(hTemplateDeviceInterfaceParametersKey);
+ }
+
+ if (hDeviceInterfaceParametersKey)
+ {
+ ZwClose(hDeviceInterfaceParametersKey);
+ }
+
+ return ntStatus;
+}
diff --git a/audio/sysvad/PhoneAudioSample/handsetspeakertopo.cpp b/audio/simpleaudiosample/Source/Main/mintopo.cpp
index 161e5bf0..6ab1624f 100644
--- a/audio/sysvad/PhoneAudioSample/handsetspeakertopo.cpp
+++ b/audio/simpleaudiosample/Source/Main/mintopo.cpp
@@ -4,37 +4,29 @@ Copyright (c) Microsoft Corporation All Rights Reserved
Module Name:
- handsetspeakertopo.cpp
+ mintopo.cpp
Abstract:
- Implementation of topology miniport for the handsetspeaker endpoint.
-
+ Implementation of topology miniport.
--*/
#pragma warning (disable : 4127)
-#include <sysvad.h>
-#include "simple.h"
+#include "definitions.h"
+#include "endpoints.h"
+#include "minwavert.h"
#include "mintopo.h"
-#include "handsetspeakertopo.h"
-#include "handsetspeakertoptable.h"
-#include <ntstrsafe.h>
-
-
-#pragma code_seg("PAGE")
//=============================================================================
+#pragma code_seg("PAGE")
NTSTATUS
-CreateHandsetSpeakerMiniportTopology
+CreateMiniportTopologySimpleAudioSample
(
- _Out_ PUNKNOWN * Unknown,
+ _Out_ PUNKNOWN * Unknown,
_In_ REFCLSID,
_In_opt_ PUNKNOWN UnknownOuter,
- _When_((PoolType & NonPagedPoolMustSucceed) != 0,
- __drv_reportError("Must succeed pool allocations are forbidden. "
- "Allocation failures cause a system crash"))
- _In_ POOL_TYPE PoolType,
+ _In_ POOL_FLAGS PoolFlags,
_In_ PUNKNOWN UnknownAdapter,
_In_opt_ PVOID DeviceContext,
_In_ PENDPOINT_MINIPAIR MiniportPair
@@ -51,15 +43,13 @@ Arguments:
RefclsId -
+ PoolType -
+
UnknownOuter -
- PoolType -
-
- UnknownAdapter -
-
- DeviceContext -
-
- MiniportPair -
+ DeviceContext -
+
+ MiniportPair -
Return Value:
@@ -69,17 +59,18 @@ Return Value:
{
PAGED_CODE();
+ UNREFERENCED_PARAMETER(UnknownAdapter);
+
ASSERT(Unknown);
ASSERT(MiniportPair);
- UNREFERENCED_PARAMETER(UnknownAdapter);
- UNREFERENCED_PARAMETER(DeviceContext);
-
- CHandsetSpeakerMiniportTopology *obj =
- new (PoolType, MINWAVERT_POOLTAG)
- CHandsetSpeakerMiniportTopology( UnknownOuter,
- MiniportPair->TopoDescriptor,
- MiniportPair->DeviceMaxChannels);
+ CMiniportTopology *obj =
+ new (PoolFlags, MINWAVERT_POOLTAG)
+ CMiniportTopology( UnknownOuter,
+ MiniportPair->TopoDescriptor,
+ MiniportPair->DeviceMaxChannels,
+ MiniportPair->DeviceType,
+ DeviceContext );
if (NULL == obj)
{
return STATUS_INSUFFICIENT_RESOURCES;
@@ -89,10 +80,11 @@ Return Value:
*Unknown = reinterpret_cast<IUnknown*>(obj);
return STATUS_SUCCESS;
-} // CreateHandsetSpeakerMiniportTopology
+} // CreateMiniportTopologySimpleAudioSample
//=============================================================================
-CHandsetSpeakerMiniportTopology::~CHandsetSpeakerMiniportTopology
+#pragma code_seg("PAGE")
+CMiniportTopology::~CMiniportTopology
(
void
)
@@ -112,19 +104,20 @@ Return Value:
{
PAGED_CODE();
- DPF_ENTER(("[CHandsetSpeakerMiniportTopology::~CHandsetSpeakerMiniportTopology]"));
-} // ~CHandsetSpeakerMiniportTopology
+ DPF_ENTER(("[CMiniportTopology::~CMiniportTopology]"));
+} // ~CMiniportTopology
//=============================================================================
+#pragma code_seg("PAGE")
NTSTATUS
-CHandsetSpeakerMiniportTopology::DataRangeIntersection
+CMiniportTopology::DataRangeIntersection
(
_In_ ULONG PinId,
_In_ PKSDATARANGE ClientDataRange,
_In_ PKSDATARANGE MyDataRange,
_In_ ULONG OutputBufferLength,
_Out_writes_bytes_to_opt_(OutputBufferLength, *ResultantFormatLength)
- PVOID ResultantFormat OPTIONAL,
+ PVOID ResultantFormat,
_Out_ PULONG ResultantFormatLength
)
/*++
@@ -163,7 +156,7 @@ Return Value:
PAGED_CODE();
return
- CMiniportTopologySYSVAD::DataRangeIntersection
+ CMiniportTopologySimpleAudioSample::DataRangeIntersection
(
PinId,
ClientDataRange,
@@ -175,8 +168,9 @@ Return Value:
} // DataRangeIntersection
//=============================================================================
+#pragma code_seg("PAGE")
STDMETHODIMP
-CHandsetSpeakerMiniportTopology::GetDescription
+CMiniportTopology::GetDescription
(
_Out_ PPCFILTER_DESCRIPTOR * OutFilterDescriptor
)
@@ -203,12 +197,13 @@ Return Value:
ASSERT(OutFilterDescriptor);
- return CMiniportTopologySYSVAD::GetDescription(OutFilterDescriptor);
+ return CMiniportTopologySimpleAudioSample::GetDescription(OutFilterDescriptor);
} // GetDescription
//=============================================================================
+#pragma code_seg("PAGE")
STDMETHODIMP
-CHandsetSpeakerMiniportTopology::Init
+CMiniportTopology::Init
(
_In_ PUNKNOWN UnknownAdapter,
_In_ PRESOURCELIST ResourceList,
@@ -239,32 +234,39 @@ Return Value:
--*/
{
UNREFERENCED_PARAMETER(ResourceList);
-
+
PAGED_CODE();
ASSERT(UnknownAdapter);
ASSERT(Port_);
- DPF_ENTER(("[CHandsetSpeakerMiniportTopology::Init]"));
+ DPF_ENTER(("[CMiniportTopology::Init]"));
NTSTATUS ntStatus;
ntStatus =
- CMiniportTopologySYSVAD::Init
+ CMiniportTopologySimpleAudioSample::Init
(
UnknownAdapter,
Port_
);
+ IF_FAILED_ACTION_JUMP(
+ ntStatus,
+ DPF(D_ERROR, ("Init: CMiniportTopologySimpleAudioSample::Init failed, 0x%x", ntStatus)),
+ Done);
+
+Done:
return ntStatus;
} // Init
//=============================================================================
+#pragma code_seg("PAGE")
STDMETHODIMP
-CHandsetSpeakerMiniportTopology::NonDelegatingQueryInterface
+CMiniportTopology::NonDelegatingQueryInterface
(
- _In_ REFIID Interface,
- _COM_Outptr_ PVOID * Object
+ _In_ REFIID Interface,
+ _COM_Outptr_ PVOID * Object
)
/*++
@@ -316,10 +318,13 @@ Return Value:
} // NonDelegatingQueryInterface
//=============================================================================
+#pragma code_seg("PAGE")
NTSTATUS
-CHandsetSpeakerMiniportTopology::PropertyHandlerJackDescription
+CMiniportTopology::PropertyHandlerJackDescription
(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG cJackDescriptions,
+ _In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION * JackDescriptions
)
/*++
@@ -329,7 +334,9 @@ Routine Description:
Arguments:
- PropertyRequest
+ PropertyRequest -
+ cJackDescriptions - # of elements in the jack descriptions array.
+ JackDescriptions - Array of jack descriptions pointers.
Return Value:
@@ -343,12 +350,9 @@ Return Value:
DPF_ENTER(("[PropertyHandlerJackDescription]"));
- ULONG cJackDescriptions = ARRAYSIZE(HandsetSpeakerJackDescriptions);
- PKSJACK_DESCRIPTION * JackDescriptions = HandsetSpeakerJackDescriptions;
-
NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
ULONG nPinId = (ULONG)-1;
-
+
if (PropertyRequest->InstanceSize >= sizeof(ULONG))
{
nPinId = *(PULONG(PropertyRequest->Instance));
@@ -400,10 +404,14 @@ Return Value:
}
//=============================================================================
+#pragma code_seg("PAGE")
NTSTATUS
-CHandsetSpeakerMiniportTopology::PropertyHandlerJackDescription2
+CMiniportTopology::PropertyHandlerJackDescription2
(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG cJackDescriptions,
+ _In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION * JackDescriptions,
+ _In_ DWORD JackCapabilities
)
/*++
@@ -413,7 +421,10 @@ Routine Description:
Arguments:
- PropertyRequest -
+ PropertyRequest -
+ cJackDescriptions - # of elements in the jack descriptions array.
+ JackDescriptions - Array of jack descriptions pointers.
+ JackCapabilities - Jack capabilities flags.
Return Value:
@@ -427,11 +438,8 @@ Return Value:
DPF_ENTER(("[PropertyHandlerJackDescription2]"));
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- ULONG nPinId = (ULONG)-1;
-
- ULONG cJackDescriptions = ARRAYSIZE(HandsetSpeakerJackDescriptions);
- PKSJACK_DESCRIPTION * JackDescriptions = HandsetSpeakerJackDescriptions;
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ ULONG nPinId = (ULONG)-1;
if (PropertyRequest->InstanceSize >= sizeof(ULONG))
{
@@ -496,8 +504,8 @@ Return Value:
// 0x00000001 - JACKDESC2_PRESENCE_DETECT_CAPABILITY
// 0x00000002 - JACKDESC2_DYNAMIC_FORMAT_CHANGE_CAPABILITY
//
- pDesc->JackCapabilities = 0;
-
+ pDesc->JackCapabilities = JackCapabilities;
+
ntStatus = STATUS_SUCCESS;
}
}
@@ -509,8 +517,9 @@ Return Value:
}
//=============================================================================
+#pragma code_seg("PAGE")
NTSTATUS
-PropertyHandler_HandsetSpeakerTopoFilter
+PropertyHandler_Topology
(
_In_ PPCPROPERTY_REQUEST PropertyRequest
)
@@ -534,28 +543,15 @@ Return Value:
ASSERT(PropertyRequest);
- DPF_ENTER(("[PropertyHandler_HandsetSpeakerTopoFilter]"));
+ DPF_ENTER(("[PropertyHandler_Topology]"));
// PropertryRequest structure is filled by portcls.
// MajorTarget is a pointer to miniport object for miniports.
//
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- PCHandsetSpeakerMiniportTopology pMiniport = (PCHandsetSpeakerMiniportTopology)PropertyRequest->MajorTarget;
-
- if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Jack))
- {
- if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION)
- {
- ntStatus = pMiniport->PropertyHandlerJackDescription(PropertyRequest);
- }
- else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION2)
- {
- ntStatus = pMiniport->PropertyHandlerJackDescription2(PropertyRequest);
- }
- }
-
- return ntStatus;
-} // PropertyHandler_HandsetSpeakerTopoFilter
-
-#pragma code_seg()
-
+ return
+ ((PCMiniportTopology)
+ (PropertyRequest->MajorTarget))->PropertyHandlerGeneric
+ (
+ PropertyRequest
+ );
+} // PropertyHandler_Topology
diff --git a/audio/simpleaudiosample/Source/Main/minwavert.cpp b/audio/simpleaudiosample/Source/Main/minwavert.cpp
new file mode 100644
index 00000000..1d92073d
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/minwavert.cpp
@@ -0,0 +1,1683 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ minwavert.cpp
+
+Abstract:
+
+ Implementation of wavert miniport.
+--*/
+
+#pragma warning (disable : 4127)
+
+#include "definitions.h"
+#include <limits.h>
+#include "endpoints.h"
+#include "minwavert.h"
+#include "minwavertstream.h"
+#include "micarraywavtable.h"
+
+#define EFFECTS_LIST_COUNT 2
+
+//=============================================================================
+// CMiniportWaveRT
+//=============================================================================
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CreateMiniportWaveRTSimpleAudioSample
+(
+ _Out_ PUNKNOWN * Unknown,
+ _In_ REFCLSID,
+ _In_opt_ PUNKNOWN UnknownOuter,
+ _In_ POOL_FLAGS PoolFlags,
+ _In_ PUNKNOWN UnknownAdapter,
+ _In_opt_ PVOID DeviceContext,
+ _In_ PENDPOINT_MINIPAIR MiniportPair
+)
+/*++
+
+Routine Description:
+
+ Create the wavert miniport.
+
+Arguments:
+
+ Unknown -
+
+ RefClsId -
+
+ UnknownOuter -
+
+ PoolType -
+
+ UnkownAdapter -
+
+ DeviceContext -
+
+ MiniportPair -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(UnknownOuter);
+
+ PAGED_CODE();
+
+ ASSERT(Unknown);
+ ASSERT(MiniportPair);
+
+ CMiniportWaveRT *obj = new (PoolFlags, MINWAVERT_POOLTAG) CMiniportWaveRT
+ (
+ UnknownAdapter,
+ MiniportPair,
+ DeviceContext
+ );
+ if (NULL == obj)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ obj->AddRef();
+ *Unknown = reinterpret_cast<IUnknown*>(obj);
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+CMiniportWaveRT::~CMiniportWaveRT
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Destructor for wavert miniport
+
+Arguments:
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::~CMiniportWaveRT]"));
+
+ if (m_pDeviceFormat)
+ {
+ ExFreePoolWithTag( m_pDeviceFormat, MINWAVERT_POOLTAG );
+ m_pDeviceFormat = NULL;
+ }
+
+ if (m_pMixFormat)
+ {
+ ExFreePoolWithTag( m_pMixFormat, MINWAVERT_POOLTAG );
+ m_pMixFormat = NULL;
+ }
+
+ if (m_pbMuted)
+ {
+ ExFreePoolWithTag(m_pbMuted, MINWAVERT_POOLTAG);
+ m_pbMuted = NULL;
+ }
+
+ if (m_plVolumeLevel)
+ {
+ ExFreePoolWithTag(m_plVolumeLevel, MINWAVERT_POOLTAG);
+ m_plVolumeLevel = NULL;
+ }
+
+ if (m_pDrmPort)
+ {
+ m_pDrmPort->Release();
+ m_pDrmPort = NULL;
+ }
+
+ if (m_pPortEvents)
+ {
+ m_pPortEvents->Release();
+ m_pPortEvents = NULL;
+ }
+
+ if (m_SystemStreams)
+ {
+ ExFreePoolWithTag( m_SystemStreams, MINWAVERT_POOLTAG );
+ m_SystemStreams = NULL;
+ }
+
+} // ~CMiniportWaveRT
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CMiniportWaveRT::DataRangeIntersection
+(
+ _In_ ULONG PinId,
+ _In_ PKSDATARANGE ClientDataRange,
+ _In_ PKSDATARANGE MyDataRange,
+ _In_ ULONG OutputBufferLength,
+ _Out_writes_bytes_to_opt_(OutputBufferLength, *ResultantFormatLength)
+ PVOID ResultantFormat,
+ _Out_ PULONG ResultantFormatLength
+)
+/*++
+
+Routine Description:
+
+ The DataRangeIntersection function determines the highest quality
+ intersection of two data ranges.
+
+ This sample just sets the ResultantFormat to be the only supported
+ format for the MicArray endpoint.
+
+Arguments:
+
+ PinId - Pin for which data intersection is being determined.
+
+ ClientDataRange - Pointer to KSDATARANGE structure which contains the data
+ range submitted by client in the data range intersection
+ property request.
+
+ MyDataRange - Pin's data range to be compared with client's data
+ range. In this case we actually ignore our own data
+ range, because we know that we only support one range.
+
+ OutputBufferLength - Size of the buffer pointed to by the resultant format
+ parameter.
+
+ ResultantFormat - Pointer to value where the resultant format should be
+ returned.
+
+ ResultantFormatLength - Actual length of the resultant format placed in
+ ResultantFormat. This should be less than or equal
+ to OutputBufferLength.
+
+ Return Value:
+
+ NT status code.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(PinId);
+
+ ULONG requiredSize;
+
+ PAGED_CODE();
+
+ if (!IsEqualGUIDAligned(ClientDataRange->Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
+ {
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ //If called for the mic array pin, set ResultantFormat to be the endpoint's only supported format.
+ //Otherwise, allow the class handler to set ResultantFormat.
+ if ((this->m_DeviceType) == eMicArrayDevice1)
+ {
+ requiredSize = sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE);
+
+ //
+ // Validate return buffer size, if the request is only for the
+ // size of the resultant structure, return it now before
+ // returning other types of errors.
+ //
+ if (!OutputBufferLength)
+ {
+ *ResultantFormatLength = requiredSize;
+ return STATUS_BUFFER_OVERFLOW;
+ }
+ else if (OutputBufferLength < requiredSize)
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ //Set ResultantFormat to be the only supported format for the MicArray endpoint.
+ PKSDATAFORMAT_WAVEFORMATEXTENSIBLE resultantFormat;
+ resultantFormat = (PKSDATAFORMAT_WAVEFORMATEXTENSIBLE)ResultantFormat;
+ *resultantFormat = *MicArrayPinSupportedDeviceFormats;
+ *ResultantFormatLength = requiredSize;
+
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ requiredSize = sizeof(KSDATAFORMAT_WAVEFORMATEX);
+
+ //
+ // Validate return buffer size, if the request is only for the
+ // size of the resultant structure, return it now before
+ // returning other types of errors.
+ //
+ if (!OutputBufferLength)
+ {
+ *ResultantFormatLength = requiredSize;
+ return STATUS_BUFFER_OVERFLOW;
+ }
+ else if (OutputBufferLength < requiredSize)
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ // Verify channel count is supported. This routine assumes a separate data
+ // range for each supported channel count.
+ if (((PKSDATARANGE_AUDIO)MyDataRange)->MaximumChannels != ((PKSDATARANGE_AUDIO)ClientDataRange)->MaximumChannels)
+ {
+ return STATUS_NO_MATCH;
+ }
+
+ //
+ // Ok, let the class handler do the rest.
+ //
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+} // DataRangeIntersection
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CMiniportWaveRT::GetDescription
+(
+ _Out_ PPCFILTER_DESCRIPTOR * OutFilterDescriptor
+)
+/*++
+
+Routine Description:
+
+ The GetDescription function gets a pointer to a filter description.
+ It provides a location to deposit a pointer in miniport's description
+ structure.
+
+Arguments:
+
+ OutFilterDescriptor - Pointer to the filter description.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(OutFilterDescriptor);
+
+ *OutFilterDescriptor = &m_FilterDesc;
+
+ return STATUS_SUCCESS;
+} // GetDescription
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CMiniportWaveRT::Init
+(
+ _In_ PUNKNOWN UnknownAdapter_,
+ _In_ PRESOURCELIST ResourceList_,
+ _In_ PPORTWAVERT Port_
+)
+/*++
+
+Routine Description:
+
+ The Init function initializes the miniport. Callers of this function
+ should run at IRQL PASSIVE_LEVEL
+
+Arguments:
+
+ UnknownAdapter - A pointer to the Iuknown interface of the adapter object.
+
+ ResourceList - Pointer to the resource list to be supplied to the miniport
+ during initialization. The port driver is free to examine the
+ contents of the ResourceList. The port driver will not be
+ modify the ResourceList contents.
+
+ Port - Pointer to the topology port object that is linked with this miniport.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(UnknownAdapter_);
+ UNREFERENCED_PARAMETER(ResourceList_);
+ UNREFERENCED_PARAMETER(Port_);
+ PAGED_CODE();
+
+ ASSERT(UnknownAdapter_);
+ ASSERT(Port_);
+
+ DPF_ENTER(("[CMiniportWaveRT::Init]"));
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ size_t size;
+
+ //
+ // Init class data members
+ //
+ m_ulSystemAllocated = 0;
+ m_SystemStreams = NULL;
+ m_bGfxEnabled = FALSE;
+ m_pMixFormat = NULL;
+ m_pDeviceFormat = NULL;
+ m_ulMixDrmContentId = 0;
+ m_pbMuted = NULL;
+ m_plVolumeLevel = NULL;
+ RtlZeroMemory(&m_MixDrmRights, sizeof(m_MixDrmRights));
+
+ //
+ // Init the audio-engine used by the render devices.
+ //
+ if (IsRenderDevice())
+ {
+ if (m_ulMaxSystemStreams == 0 )
+ {
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ // System streams.
+ size = sizeof(PCMiniportWaveRTStream) * m_ulMaxSystemStreams;
+ m_SystemStreams = (PCMiniportWaveRTStream *)ExAllocatePool2(POOL_FLAG_NON_PAGED, size, MINWAVERT_POOLTAG);
+ if (m_SystemStreams == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // For DRM support.
+ //
+ if (!NT_SUCCESS(Port_->QueryInterface(IID_IDrmPort2, (PVOID *)&m_pDrmPort)))
+ {
+ m_pDrmPort = NULL;
+ }
+ }
+
+ //
+ // For KS event support.
+ //
+ if (!NT_SUCCESS(Port_->QueryInterface(IID_IPortEvents, (PVOID *)&m_pPortEvents)))
+ {
+ m_pPortEvents = NULL;
+ }
+
+ return ntStatus;
+} // Init
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CMiniportWaveRT::NewStream
+(
+ _Out_ PMINIPORTWAVERTSTREAM * OutStream,
+ _In_ PPORTWAVERTSTREAM OuterUnknown,
+ _In_ ULONG Pin,
+ _In_ BOOLEAN Capture,
+ _In_ PKSDATAFORMAT DataFormat
+)
+/*++
+
+Routine Description:
+
+ The NewStream function creates a new instance of a logical stream
+ associated with a specified physical channel. Callers of NewStream should
+ run at IRQL PASSIVE_LEVEL.
+
+Arguments:
+
+ OutStream -
+
+ OuterUnknown -
+
+ Pin -
+
+ Capture -
+
+ DataFormat -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(OutStream);
+ ASSERT(DataFormat);
+
+ DPF_ENTER(("[CMiniportWaveRT::NewStream]"));
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ PCMiniportWaveRTStream stream = NULL;
+ GUID signalProcessingMode = AUDIO_SIGNALPROCESSINGMODE_DEFAULT;
+
+ *OutStream = NULL;
+
+ //
+ // If the data format attributes were specified, extract them.
+ //
+ if ( DataFormat->Flags & KSDATAFORMAT_ATTRIBUTES )
+ {
+ // The attributes are aligned (QWORD alignment) after the data format
+ PKSMULTIPLE_ITEM attributes = (PKSMULTIPLE_ITEM) (((PBYTE)DataFormat) + ((DataFormat->FormatSize + FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT));
+ ntStatus = GetAttributesFromAttributeList(attributes, attributes->Size, &signalProcessingMode);
+ }
+
+ // Check if we have enough streams.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = ValidateStreamCreate(Pin, Capture);
+ }
+
+ // Determine if the format is valid.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = IsFormatSupported(Pin, Capture, DataFormat);
+ }
+
+ // Instantiate a stream. Stream must be in
+ // NonPagedPool(Nx) because of file saving.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ stream = new (POOL_FLAG_NON_PAGED, MINWAVERT_POOLTAG)
+ CMiniportWaveRTStream(NULL);
+
+ if (stream)
+ {
+ stream->AddRef();
+
+ ntStatus =
+ stream->Init
+ (
+ this,
+ OuterUnknown,
+ Pin,
+ Capture,
+ DataFormat,
+ signalProcessingMode
+ );
+ }
+ else
+ {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ *OutStream = PMINIPORTWAVERTSTREAM(stream);
+ (*OutStream)->AddRef();
+
+ // The stream has references now for the caller. The caller expects these
+ // references to be there.
+ }
+
+ // This is our private reference to the stream. The caller has
+ // its own, so we can release in any case.
+ //
+ if (stream)
+ {
+ stream->Release();
+ }
+
+ return ntStatus;
+} // NewStream
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CMiniportWaveRT::NonDelegatingQueryInterface
+(
+ _In_ REFIID Interface,
+ _COM_Outptr_ PVOID * Object
+)
+/*++
+
+Routine Description:
+
+ QueryInterface
+
+Arguments:
+
+ Interface - GUID
+
+ Object - interface pointer to be returned.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(Object);
+
+ if (IsEqualGUIDAligned(Interface, IID_IUnknown))
+ {
+ *Object = PVOID(PUNKNOWN(PMINIPORTWAVERT(this)));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniport))
+ {
+ *Object = PVOID(PMINIPORT(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveRT))
+ {
+ *Object = PVOID(PMINIPORTWAVERT(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniportAudioSignalProcessing))
+ {
+ *Object = PVOID(PMINIPORTAudioSignalProcessing(this));
+ }
+ else
+ {
+ *Object = NULL;
+ }
+
+ if (*Object)
+ {
+ // We reference the interface for the caller.
+
+ PUNKNOWN(*Object)->AddRef();
+ return STATUS_SUCCESS;
+ }
+
+ return STATUS_INVALID_PARAMETER;
+} // NonDelegatingQueryInterface
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::GetDeviceDescription(_Out_ PDEVICE_DESCRIPTION DmaDeviceDescription)
+{
+ PAGED_CODE ();
+
+ ASSERT (DmaDeviceDescription);
+
+ DPF_ENTER(("[CMiniportWaveRT::GetDeviceDescription]"));
+
+ RtlZeroMemory (DmaDeviceDescription, sizeof (DEVICE_DESCRIPTION));
+
+ //
+ // Init device description. This sample is using the same info for all m_DeviceType(s).
+ //
+
+ DmaDeviceDescription->Master = TRUE;
+ DmaDeviceDescription->ScatterGather = TRUE;
+ DmaDeviceDescription->Dma32BitAddresses = TRUE;
+ DmaDeviceDescription->InterfaceType = PCIBus;
+ DmaDeviceDescription->MaximumLength = 0xFFFFFFFF;
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::GetModes
+(
+ _In_ ULONG Pin,
+ _Out_writes_opt_(*NumSignalProcessingModes) GUID* SignalProcessingModes,
+ _Inout_ ULONG* NumSignalProcessingModes
+)
+/*
+
+1. If Pin is not a valid pin number,
+ return STATUS_INVALID_PARAMETER.
+
+2. If Pin is a valid pin number and it supports n modes (n>0),
+ init out-parameters and return STATUS_SUCCESS.
+
+3. Else this pin doesn't support any mode,
+ return STATUS_NOT_SUPPORTED.
+ example: bridge pins or another mode-not-aware pins.
+
+*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::GetModes]"));
+
+ NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
+ ULONG numModes = 0;
+ MODE_AND_DEFAULT_FORMAT *modeInfo = NULL;
+
+ if (Pin >= m_pMiniportPair->WaveDescriptor->PinCount)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // This method is valid only on the following pins:
+ // render is offload capable:
+ // sink (#0) and offload (#1) pins.
+ // render is NOT offload capable:
+ // sink (#0) pin.
+ // capture device:
+ // source (#1) pin.
+ //
+ numModes = GetPinSupportedDeviceModes(Pin, &modeInfo);
+ if (numModes == 0)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ // If caller requests the modes, verify sufficient buffer size then return the modes
+ if (SignalProcessingModes != NULL)
+ {
+ if (*NumSignalProcessingModes < numModes)
+ {
+ *NumSignalProcessingModes = numModes;
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ for (ULONG i=0; i<numModes; ++i)
+ {
+ SignalProcessingModes[i] = modeInfo[i].Mode;
+ }
+ }
+
+ ASSERT(numModes > 0);
+ *NumSignalProcessingModes = numModes;
+ ntStatus = STATUS_SUCCESS;
+
+Done:
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::ValidateStreamCreate
+(
+ _In_ ULONG _Pin,
+ _In_ BOOLEAN _Capture
+)
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::ValidateStreamCreate]"));
+
+ NTSTATUS ntStatus = STATUS_NOT_SUPPORTED;
+
+ if (_Capture)
+ {
+
+ if (IsSystemCapturePin(_Pin))
+ {
+ VERIFY_PIN_INSTANCE_RESOURCES_AVAILABLE(ntStatus, m_ulSystemAllocated, m_ulMaxSystemStreams);
+ }
+
+ }
+ else
+ {
+
+ if (IsSystemRenderPin(_Pin))
+ {
+ VERIFY_PIN_INSTANCE_RESOURCES_AVAILABLE(ntStatus, m_ulSystemAllocated, m_ulMaxSystemStreams);
+ }
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg()
+_Use_decl_annotations_
+VOID CMiniportWaveRT::AcquireFormatsAndModesLock()
+{
+ KeAcquireSpinLock(&m_DeviceFormatsAndModesLock, &m_DeviceFormatsAndModesIrql);
+}
+
+#pragma code_seg()
+_Use_decl_annotations_
+VOID CMiniportWaveRT::ReleaseFormatsAndModesLock()
+{
+ KeReleaseSpinLock(&m_DeviceFormatsAndModesLock, m_DeviceFormatsAndModesIrql);
+}
+
+//---------------------------------------------------------------------------
+// GetPinSupportedDeviceFormats
+//
+// Return supported formats for a given pin.
+//
+// Return value
+// The number of KSDATAFORMAT_WAVEFORMATEXTENSIBLE items.
+//
+// Remarks
+// Supported formats index array follows same order as filter's pin
+// descriptor list.
+//
+#pragma code_seg()
+_Use_decl_annotations_
+ULONG CMiniportWaveRT::GetPinSupportedDeviceFormats(_In_ ULONG PinId, _Outptr_opt_result_buffer_(return) KSDATAFORMAT_WAVEFORMATEXTENSIBLE **ppFormats)
+{
+ PPIN_DEVICE_FORMATS_AND_MODES pDeviceFormatsAndModes = NULL;
+
+ AcquireFormatsAndModesLock();
+
+ pDeviceFormatsAndModes = m_DeviceFormatsAndModes;
+ ASSERT(m_DeviceFormatsAndModesCount > PinId);
+ ASSERT(pDeviceFormatsAndModes[PinId].WaveFormats != NULL);
+ ASSERT(pDeviceFormatsAndModes[PinId].WaveFormatsCount > 0);
+
+ if (ppFormats != NULL)
+ {
+ *ppFormats = pDeviceFormatsAndModes[PinId].WaveFormats;
+ }
+
+ ReleaseFormatsAndModesLock();
+
+ return pDeviceFormatsAndModes[PinId].WaveFormatsCount;
+}
+
+//---------------------------------------------------------------------------
+// GetPinSupportedDeviceModes
+//
+// Return mode information for a given pin.
+//
+// Return value
+// The number of MODE_AND_DEFAULT_FORMAT items or 0 if none.
+//
+// Remarks
+// Supported formats index array follows same order as filter's pin
+// descriptor list.
+//
+#pragma code_seg()
+_Use_decl_annotations_
+ULONG CMiniportWaveRT::GetPinSupportedDeviceModes(_In_ ULONG PinId, _Outptr_opt_result_buffer_(return) _On_failure_(_Deref_post_null_) MODE_AND_DEFAULT_FORMAT **ppModes)
+{
+ PMODE_AND_DEFAULT_FORMAT modes;
+ ULONG numModes;
+
+ AcquireFormatsAndModesLock();
+
+ ASSERT(m_DeviceFormatsAndModesCount > PinId);
+ ASSERT((m_DeviceFormatsAndModes[PinId].ModeAndDefaultFormatCount == 0) == (m_DeviceFormatsAndModes[PinId].ModeAndDefaultFormat == NULL));
+
+ modes = m_DeviceFormatsAndModes[PinId].ModeAndDefaultFormat;
+ numModes = m_DeviceFormatsAndModes[PinId].ModeAndDefaultFormatCount;
+
+ if (ppModes != NULL)
+ {
+ if (numModes > 0)
+ {
+ *ppModes = modes;
+ }
+ else
+ {
+ // ensure that the returned pointer is NULL
+ // in the event of failure (SAL annotation above
+ // indicates that it must be NULL, and OACR sees a possibility
+ // that it might not be).
+ *ppModes = NULL;
+ }
+ }
+
+ ReleaseFormatsAndModesLock();
+ return numModes;
+}
+
+#pragma code_seg()
+BOOL CMiniportWaveRT::IsSystemCapturePin(ULONG nPinId)
+{
+ AcquireFormatsAndModesLock();
+
+ PINTYPE pinType = m_DeviceFormatsAndModes[nPinId].PinType;
+
+ ReleaseFormatsAndModesLock();
+ return (pinType == SystemCapturePin);
+}
+
+#pragma code_seg()
+BOOL CMiniportWaveRT::IsSystemRenderPin(ULONG nPinId)
+{
+ AcquireFormatsAndModesLock();
+
+ PINTYPE pinType = m_DeviceFormatsAndModes[nPinId].PinType;
+
+ ReleaseFormatsAndModesLock();
+ return (pinType == SystemRenderPin);
+}
+
+#pragma code_seg()
+BOOL CMiniportWaveRT::IsBridgePin(ULONG nPinId)
+{
+ AcquireFormatsAndModesLock();
+
+ PINTYPE pinType = m_DeviceFormatsAndModes[nPinId].PinType;
+
+ ReleaseFormatsAndModesLock();
+ return (pinType == BridgePin);
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::StreamCreated
+(
+ _In_ ULONG _Pin,
+ _In_ PCMiniportWaveRTStream _Stream
+)
+{
+ PAGED_CODE();
+
+ PCMiniportWaveRTStream * streams = NULL;
+ ULONG count = 0;
+
+ DPF_ENTER(("[CMiniportWaveRT::StreamCreated]"));
+
+ if (IsSystemCapturePin(_Pin))
+ {
+ ALLOCATE_PIN_INSTANCE_RESOURCES(m_ulSystemAllocated);
+ return STATUS_SUCCESS;
+ }
+ else if (IsSystemRenderPin(_Pin))
+ {
+
+ ALLOCATE_PIN_INSTANCE_RESOURCES(m_ulSystemAllocated);
+ streams = m_SystemStreams;
+ count = m_ulMaxSystemStreams;
+
+ }
+
+ //
+ // Cache this stream's ptr.
+ //
+ if (streams != NULL)
+ {
+ ULONG i = 0;
+ for (; i<count; ++i)
+ {
+ if (streams[i] == NULL)
+ {
+ streams[i] = _Stream;
+ break;
+ }
+ }
+ ASSERT(i != count);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::StreamClosed
+(
+ _In_ ULONG _Pin,
+ _In_ PCMiniportWaveRTStream _Stream
+)
+{
+ PAGED_CODE();
+
+ bool updateDrmRights = false;
+ PCMiniportWaveRTStream * streams = NULL;
+ ULONG count = 0;
+
+ DPF_ENTER(("[CMiniportWaveRT::StreamClosed]"));
+
+ if (IsSystemCapturePin(_Pin))
+ {
+ FREE_PIN_INSTANCE_RESOURCES(m_ulSystemAllocated);
+ return STATUS_SUCCESS;
+ }
+ else if (IsSystemRenderPin(_Pin))
+ {
+
+ FREE_PIN_INSTANCE_RESOURCES(m_ulSystemAllocated);
+ streams = m_SystemStreams;
+ count = m_ulMaxSystemStreams;
+ updateDrmRights = true;
+
+ }
+
+ //
+ // Cleanup.
+ //
+ if (streams != NULL)
+ {
+ ULONG i = 0;
+ for (; i<count; ++i)
+ {
+ if (streams[i] == _Stream)
+ {
+ streams[i] = NULL;
+ break;
+ }
+ }
+ ASSERT(i != count);
+ }
+
+ //
+ // Update mixed drm rights.
+ //
+ if (updateDrmRights)
+ {
+ UpdateDrmRights();
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::GetAttributesFromAttributeList
+(
+ _In_ const KSMULTIPLE_ITEM *_pAttributes,
+ _In_ size_t _Size,
+ _Out_ GUID* _pSignalProcessingMode
+)
+/*++
+
+Routine Description:
+
+ Processes attributes list and return known attributes.
+
+Arguments:
+
+ _pAttributes - pointer to KSMULTIPLE_ITEM at head of an attributes list.
+
+ _Size - count of bytes in the buffer pointed to by _pAttributes. The routine
+ verifies sufficient buffer size while processing the attributes.
+
+ _pSignalProcessingMode - returns the signal processing mode extracted from
+ the attribute list, or AUDIO_SIGNALPROCESSINGMODE_DEFAULT if the attribute
+ is not present in the list.
+
+Return Value:
+
+ NT status code.
+
+Remarks
+
+ This function is currently written for a single supported attribute
+ (KSATTRIBUTEID_AUDIOSIGNALPROCESSING_MODE). As additional attributes are defined in the future,
+ this function should be rewritten to be data driven through tables, etc.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::GetAttributesFromAttributeList]"));
+
+ size_t cbRemaining = _Size;
+
+ *_pSignalProcessingMode = AUDIO_SIGNALPROCESSINGMODE_DEFAULT;
+
+ if (cbRemaining < sizeof(KSMULTIPLE_ITEM))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+ cbRemaining -= sizeof(KSMULTIPLE_ITEM);
+
+ //
+ // Extract attributes.
+ //
+ PKSATTRIBUTE attributeHeader = (PKSATTRIBUTE)(_pAttributes + 1);
+
+ for (ULONG i = 0; i < _pAttributes->Count; i++)
+ {
+ if (cbRemaining < sizeof(KSATTRIBUTE))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (attributeHeader->Attribute == KSATTRIBUTEID_AUDIOSIGNALPROCESSING_MODE)
+ {
+ KSATTRIBUTE_AUDIOSIGNALPROCESSING_MODE* signalProcessingModeAttribute;
+
+ if (cbRemaining < sizeof(KSATTRIBUTE_AUDIOSIGNALPROCESSING_MODE))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (attributeHeader->Size != sizeof(KSATTRIBUTE_AUDIOSIGNALPROCESSING_MODE))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ signalProcessingModeAttribute = (KSATTRIBUTE_AUDIOSIGNALPROCESSING_MODE*)attributeHeader;
+
+ // Return mode to caller.
+ *_pSignalProcessingMode = signalProcessingModeAttribute->SignalProcessingMode;
+ }
+ else
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ // Adjust pointer and buffer size to next attribute (QWORD aligned)
+ ULONG cbAttribute = ((attributeHeader->Size + FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT);
+
+ attributeHeader = (PKSATTRIBUTE) (((PBYTE)attributeHeader) + cbAttribute);
+ cbRemaining -= cbAttribute;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::IsFormatSupported
+(
+ _In_ ULONG _ulPin,
+ _In_ BOOLEAN _bCapture,
+ _In_ PKSDATAFORMAT _pDataFormat
+)
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::IsFormatSupported]"));
+
+ NTSTATUS ntStatus = STATUS_NO_MATCH;
+ PKSDATAFORMAT_WAVEFORMATEXTENSIBLE pPinFormats = NULL;
+ ULONG cPinFormats = 0;
+
+ UNREFERENCED_PARAMETER(_bCapture);
+
+ if (_ulPin >= m_pMiniportPair->WaveDescriptor->PinCount)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ cPinFormats = GetPinSupportedDeviceFormats(_ulPin, &pPinFormats);
+
+ for (UINT iFormat = 0; iFormat < cPinFormats; iFormat++)
+ {
+ PKSDATAFORMAT_WAVEFORMATEXTENSIBLE pFormat = &pPinFormats[iFormat];
+ // KSDATAFORMAT VALIDATION
+ if (!IsEqualGUIDAligned(pFormat->DataFormat.MajorFormat, _pDataFormat->MajorFormat)) { continue; }
+ if (!IsEqualGUIDAligned(pFormat->DataFormat.SubFormat, _pDataFormat->SubFormat)) { continue; }
+ if (!IsEqualGUIDAligned(pFormat->DataFormat.Specifier, _pDataFormat->Specifier)) { continue; }
+ if (pFormat->DataFormat.FormatSize < sizeof(KSDATAFORMAT_WAVEFORMATEX)) { continue; }
+
+ // WAVEFORMATEX VALIDATION
+ PWAVEFORMATEX pWaveFormat = reinterpret_cast<PWAVEFORMATEX>(_pDataFormat + 1);
+
+ if (pWaveFormat->wFormatTag != WAVE_FORMAT_EXTENSIBLE)
+ {
+ if (pWaveFormat->wFormatTag != EXTRACT_WAVEFORMATEX_ID(&(pFormat->WaveFormatExt.SubFormat))) { continue; }
+ }
+ if (pWaveFormat->nChannels != pFormat->WaveFormatExt.Format.nChannels) { continue; }
+ if (pWaveFormat->nSamplesPerSec != pFormat->WaveFormatExt.Format.nSamplesPerSec) { continue; }
+ if (pWaveFormat->nBlockAlign != pFormat->WaveFormatExt.Format.nBlockAlign) { continue; }
+ if (pWaveFormat->wBitsPerSample != pFormat->WaveFormatExt.Format.wBitsPerSample) { continue; }
+ if (pWaveFormat->wFormatTag != WAVE_FORMAT_EXTENSIBLE)
+ {
+ ntStatus = STATUS_SUCCESS;
+ break;
+ }
+
+ // WAVEFORMATEXTENSIBLE VALIDATION
+ if (pWaveFormat->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) { continue; }
+
+ PWAVEFORMATEXTENSIBLE pWaveFormatExt = reinterpret_cast<PWAVEFORMATEXTENSIBLE>(pWaveFormat);
+ if (pWaveFormatExt->Samples.wValidBitsPerSample != pFormat->WaveFormatExt.Samples.wValidBitsPerSample) { continue; }
+ if (pWaveFormatExt->dwChannelMask != pFormat->WaveFormatExt.dwChannelMask) { continue; }
+ if (!IsEqualGUIDAligned(pWaveFormatExt->SubFormat, pFormat->WaveFormatExt.SubFormat)) { continue; }
+
+ ntStatus = STATUS_SUCCESS;
+ break;
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::PropertyHandlerProposedFormat
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+{
+ PKSP_PIN kspPin = NULL;
+ PKSDATAFORMAT pKsFormat = NULL;
+ ULONG cbMinSize = 0;
+ NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
+
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::PropertyHandlerProposedFormat]"));
+
+ // All properties handled by this handler require at least a KSP_PIN descriptor.
+
+ // Verify instance data stores at least KSP_PIN fields beyond KSPPROPERTY.
+ if (PropertyRequest->InstanceSize < (sizeof(KSP_PIN) - RTL_SIZEOF_THROUGH_FIELD(KSP_PIN, Property)))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // Extract property descriptor from property request instance data
+ kspPin = CONTAINING_RECORD(PropertyRequest->Instance, KSP_PIN, PinId);
+
+ //
+ // This method is valid only on streaming pins.
+ //
+ if (IsSystemRenderPin(kspPin->PinId) ||
+ IsSystemCapturePin(kspPin->PinId))
+ {
+ ntStatus = STATUS_SUCCESS;
+ }
+ else if (IsBridgePin(kspPin->PinId))
+ {
+ ntStatus = STATUS_NOT_SUPPORTED;
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return ntStatus;
+ }
+
+ cbMinSize = sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE);
+
+ // Handle KSPROPERTY_TYPE_BASICSUPPORT query
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ULONG flags = PropertyRequest->PropertyItem->Flags;
+
+ return PropertyHandler_BasicSupport(PropertyRequest, flags, VT_ILLEGAL);
+ }
+
+ // Verify value size
+ if (PropertyRequest->ValueSize == 0)
+ {
+ PropertyRequest->ValueSize = cbMinSize;
+ return STATUS_BUFFER_OVERFLOW;
+ }
+ if (PropertyRequest->ValueSize < cbMinSize)
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ pKsFormat = (PKSDATAFORMAT)PropertyRequest->Value;
+ ntStatus = IsFormatSupported(kspPin->PinId, IsSystemCapturePin(kspPin->PinId) || FALSE, pKsFormat);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return ntStatus;
+ }
+ }
+
+ return ntStatus;
+} // PropertyHandlerProposedFormat
+
+//=============================================================================
+#pragma code_seg()
+NTSTATUS
+CMiniportWaveRT_EventHandler_PinCapsChange
+(
+_In_ PPCEVENT_REQUEST EventRequest
+)
+{
+ CMiniportWaveRT* miniport = reinterpret_cast<CMiniportWaveRT*>(EventRequest->MajorTarget);
+ return miniport->EventHandler_PinCapsChange(EventRequest);
+}
+
+//=============================================================================
+#pragma code_seg()
+NTSTATUS
+CMiniportWaveRT::EventHandler_PinCapsChange
+(
+_In_ PPCEVENT_REQUEST EventRequest
+)
+{
+ if (*EventRequest->EventItem->Set != KSEVENTSETID_PinCapsChange)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ switch (EventRequest->Verb)
+ {
+ // Do we support event handling?!?
+ case PCEVENT_VERB_SUPPORT:
+ break;
+ // We should add the event now!
+ case PCEVENT_VERB_ADD:
+ // If we have the interface and EventEntry is defined ...
+ if (EventRequest->EventEntry)
+ {
+ switch (EventRequest->EventItem->Id)
+ {
+ // Add pincaps format change event to support the force sample rate feature
+ case KSEVENT_PINCAPS_FORMATCHANGE:
+ m_pPortEvents->AddEventToEventList(EventRequest->EventEntry);
+ break;
+ default:
+ return STATUS_INVALID_PARAMETER;
+ break;
+ }
+ }
+ else
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+ break;
+
+ case PCEVENT_VERB_REMOVE:
+ // We cannot remove the event but we can stop generating the
+ // events. However, it also doesn't hurt to always generate them ...
+ break;
+
+ default:
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::PropertyHandlerProposedFormat2
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+{
+ PKSP_PIN kspPin = NULL;
+ ULONG cbMinSize = 0;
+ NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
+ ULONG numModes = 0;
+ MODE_AND_DEFAULT_FORMAT *modeInfo = NULL;
+ MODE_AND_DEFAULT_FORMAT *modeTemp = NULL;
+ PKSMULTIPLE_ITEM pKsItemsHeader = NULL;
+ PKSMULTIPLE_ITEM pKsItemsHeaderOut = NULL;
+ size_t cbItemsList = 0;
+ GUID signalProcessingMode = {0};
+ BOOLEAN bFound = FALSE;
+ ULONG i;
+
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::PropertyHandlerProposedFormat2]"));
+
+ // All properties handled by this handler require at least a KSP_PIN descriptor.
+
+ // Verify instance data stores at least KSP_PIN fields beyond KSPPROPERTY.
+ if (PropertyRequest->InstanceSize < (sizeof(KSP_PIN) - RTL_SIZEOF_THROUGH_FIELD(KSP_PIN, Property)))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // Extract property descriptor from property request instance data
+ kspPin = CONTAINING_RECORD(PropertyRequest->Instance, KSP_PIN, PinId);
+
+ if (kspPin->PinId >= m_pMiniportPair->WaveDescriptor->PinCount)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // This property is supported only on some streaming pins.
+ //
+ numModes = GetPinSupportedDeviceModes(kspPin->PinId, &modeInfo);
+
+ ASSERT((modeInfo != NULL && numModes > 0) || (modeInfo == NULL && numModes == 0));
+
+ if (modeInfo == NULL)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ //
+ // Even for pins that support modes, the pin might not support proposed formats
+ //
+ bFound = FALSE;
+ for (i=0, modeTemp=modeInfo; i<numModes; ++i, ++modeTemp)
+ {
+ if (modeTemp->DefaultFormat != NULL)
+ {
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ if (!bFound)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ //
+ // The property is generally supported on this pin. Handle basic support request.
+ //
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ return PropertyHandler_BasicSupport(PropertyRequest, PropertyRequest->PropertyItem->Flags, VT_ILLEGAL);
+ }
+
+ //
+ // Get the mode if specified.
+ //
+ pKsItemsHeader = (PKSMULTIPLE_ITEM)(kspPin + 1);
+ cbItemsList = (((PBYTE)PropertyRequest->Instance) + PropertyRequest->InstanceSize) - (PBYTE)pKsItemsHeader;
+
+ ntStatus = GetAttributesFromAttributeList(pKsItemsHeader, cbItemsList, &signalProcessingMode);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return ntStatus;
+ }
+
+ //
+ // Get the info associated with this mode.
+ //
+ bFound = FALSE;
+ for (i=0; i<numModes; ++i, ++modeInfo)
+ {
+ if (modeInfo->Mode == signalProcessingMode)
+ {
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ // Either the mode isn't supported, or the driver doesn't support a
+ // proprosed format for this specific mode.
+ if (!bFound || modeInfo->DefaultFormat == NULL)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ //
+ // Compute output data buffer.
+ //
+ cbMinSize = modeInfo->DefaultFormat->FormatSize;
+ cbMinSize = (cbMinSize + 7) & ~7;
+
+ pKsItemsHeaderOut = (PKSMULTIPLE_ITEM)((PBYTE)PropertyRequest->Value + cbMinSize);
+
+ if (cbItemsList > MAXULONG)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // Total # of bytes.
+ ntStatus = RtlULongAdd(cbMinSize, (ULONG)cbItemsList, &cbMinSize);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // Property not supported.
+ if (cbMinSize == 0)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ // Verify value size
+ if (PropertyRequest->ValueSize == 0)
+ {
+ PropertyRequest->ValueSize = cbMinSize;
+ return STATUS_BUFFER_OVERFLOW;
+ }
+ if (PropertyRequest->ValueSize < cbMinSize)
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ // Only GET is supported for this property
+ if ((PropertyRequest->Verb & KSPROPERTY_TYPE_GET) == 0)
+ {
+ return STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ // Copy the proposed default format.
+ RtlCopyMemory(PropertyRequest->Value, modeInfo->DefaultFormat, modeInfo->DefaultFormat->FormatSize);
+
+ // Copy back the attribute list.
+ ASSERT(cbItemsList > 0);
+ ((KSDATAFORMAT*)PropertyRequest->Value)->Flags = KSDATAFORMAT_ATTRIBUTES;
+ RtlCopyMemory(pKsItemsHeaderOut, pKsItemsHeader, cbItemsList);
+
+ PropertyRequest->ValueSize = cbMinSize;
+
+ return STATUS_SUCCESS;
+} // PropertyHandlerProposedFormat
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+CMiniportWaveRT::UpdateDrmRights
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Updates the mixed DrmRights. This is done by creating an array of existing
+ content ids and asking DrmPort to create a new contend id with a mixed
+ DrmRights structure.
+ The new DrmRights structure should be enforced, if everything goes well.
+
+Arguments:
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::UpdateDrmRights]"));
+
+ NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
+ ULONG ulMixDrmContentId = 0;
+ BOOL fCreatedContentId = FALSE;
+ DRMRIGHTS MixDrmRights = {FALSE, 0, FALSE};
+ ULONG ulContentIndex = 0;
+ ULONG* ulContentIds = NULL;
+
+ //
+ // This function only runs if IID_DrmPort is implemented in Wave port.
+ //
+ if (!m_pDrmPort)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ ulContentIds = new (POOL_FLAG_NON_PAGED, MINWAVERT_POOLTAG) ULONG[m_ulMaxSystemStreams + m_ulMaxOffloadStreams];
+ if (!ulContentIds)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Create an array of all StreamIds.
+ //
+ for (ULONG i = 0; i < m_ulMaxSystemStreams; i++)
+ {
+ if (m_SystemStreams[i])
+ {
+ ulContentIds[ulContentIndex] = m_SystemStreams[i]->m_ulContentId;
+ ulContentIndex++;
+ }
+ }
+
+ //
+ // Create the new contentId.
+ //
+ if (ulContentIndex)
+ {
+ ntStatus =
+ m_pDrmPort->CreateContentMixed
+ (
+ ulContentIds,
+ ulContentIndex,
+ &ulMixDrmContentId
+ );
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ fCreatedContentId = TRUE;
+ ntStatus =
+ m_pDrmPort->GetContentRights
+ (
+ ulMixDrmContentId,
+ &MixDrmRights
+ );
+ }
+ }
+
+ //
+ // If successful, destroy the old ContentId and update global rights.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ m_pDrmPort->DestroyContent(m_ulMixDrmContentId);
+ m_ulMixDrmContentId = ulMixDrmContentId;
+ RtlCopyMemory(&m_MixDrmRights, &MixDrmRights, sizeof(m_MixDrmRights));
+
+ //
+ // At this point the driver should enforce the new DrmRights.
+ // The sample driver handles DrmRights per stream basis, and
+ // stops writing the stream to disk, if CopyProtect = TRUE.
+ //
+ }
+
+ //
+ // Cleanup if failed
+ //
+ if (!NT_SUCCESS(ntStatus) && fCreatedContentId)
+ {
+ m_pDrmPort->DestroyContent(ulMixDrmContentId);
+ }
+
+ //
+ // Free allocated memory.
+ //
+ ASSERT(ulContentIds);
+ delete [] ulContentIds;
+ ulContentIds = NULL;
+
+ return ntStatus;
+} // UpdateDrmRights
+
+#pragma code_seg("PAGE")
+NTSTATUS
+PropertyHandler_WaveFilter
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Redirects general property request to miniport object
+
+Arguments:
+
+ PropertyRequest -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ CMiniportWaveRT* pWaveHelper = reinterpret_cast<CMiniportWaveRT*>(PropertyRequest->MajorTarget);
+
+ if (pWaveHelper == NULL)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ pWaveHelper->AddRef();
+
+
+ if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Pin))
+ {
+ switch (PropertyRequest->PropertyItem->Id)
+ {
+ case KSPROPERTY_PIN_PROPOSEDATAFORMAT:
+ ntStatus = pWaveHelper->PropertyHandlerProposedFormat(PropertyRequest);
+ break;
+
+ case KSPROPERTY_PIN_PROPOSEDATAFORMAT2:
+ ntStatus = pWaveHelper->PropertyHandlerProposedFormat2(PropertyRequest);
+ break;
+
+ default:
+ DPF(D_TERSE, ("[PropertyHandler_WaveFilter: Invalid Device Request]"));
+ }
+ }
+
+ pWaveHelper->Release();
+
+ return ntStatus;
+} // PropertyHandler_WaveFilter
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+PropertyHandler_GenericPin
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+{
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ CMiniportWaveRT* pWave = NULL;
+ CMiniportWaveRTStream * pStream = NULL;
+
+ PAGED_CODE();
+
+ if (PropertyRequest->MajorTarget == NULL ||
+ PropertyRequest->MinorTarget == NULL)
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ //
+ // Get a ref to the miniport.
+ //
+ pWave = MajorTarget_to_Obj(PropertyRequest->MajorTarget);
+ pWave->AddRef();
+
+ //
+ // Get a ref to the stream.
+ //
+ pStream = MinorTarget_to_Obj(PropertyRequest->MinorTarget);
+ pStream->AddRef();
+
+exit:
+
+ SAFE_RELEASE(pStream);
+ SAFE_RELEASE(pWave);
+
+ return ntStatus;
+}
+
+#pragma code_seg()
+
diff --git a/audio/simpleaudiosample/Source/Main/minwavert.h b/audio/simpleaudiosample/Source/Main/minwavert.h
new file mode 100644
index 00000000..4c0ccd83
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/minwavert.h
@@ -0,0 +1,302 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ minwavert.h
+
+Abstract:
+
+ Definition of wavert miniport class.
+--*/
+
+#ifndef _SIMPLEAUDIOSAMPLE_MINWAVERT_H_
+#define _SIMPLEAUDIOSAMPLE_MINWAVERT_H_
+
+//=============================================================================
+// Referenced Forward
+//=============================================================================
+class CMiniportWaveRTStream;
+typedef CMiniportWaveRTStream *PCMiniportWaveRTStream;
+
+//=============================================================================
+// Classes
+//=============================================================================
+///////////////////////////////////////////////////////////////////////////////
+// CMiniportWaveRT
+//
+class CMiniportWaveRT :
+ public IMiniportWaveRT,
+ public IMiniportAudioSignalProcessing,
+ public CUnknown
+{
+private:
+ ULONG m_ulSystemAllocated;
+
+ ULONG m_ulMaxSystemStreams;
+ ULONG m_ulMaxOffloadStreams;
+ ULONG m_ulMaxLoopbackStreams;
+
+ // weak ref of running streams.
+ PCMiniportWaveRTStream * m_SystemStreams;
+
+ BOOL m_bGfxEnabled;
+ PBOOL m_pbMuted;
+ PLONG m_plVolumeLevel;
+ PKSDATAFORMAT_WAVEFORMATEXTENSIBLE m_pMixFormat;
+ PKSDATAFORMAT_WAVEFORMATEXTENSIBLE m_pDeviceFormat;
+ PCFILTER_DESCRIPTOR m_FilterDesc;
+ PIN_DEVICE_FORMATS_AND_MODES * m_DeviceFormatsAndModes;
+ KSPIN_LOCK m_DeviceFormatsAndModesLock; // To serialize access.
+ KIRQL m_DeviceFormatsAndModesIrql;
+ ULONG m_DeviceFormatsAndModesCount;
+ USHORT m_DeviceMaxChannels;
+ PDRMPORT m_pDrmPort;
+ DRMRIGHTS m_MixDrmRights;
+ ULONG m_ulMixDrmContentId;
+
+ union {
+ PVOID m_DeviceContext;
+ };
+
+protected:
+ PADAPTERCOMMON m_pAdapterCommon;
+ ULONG m_DeviceFlags;
+ eDeviceType m_DeviceType;
+ PPORTEVENTS m_pPortEvents;
+ PENDPOINT_MINIPAIR m_pMiniportPair;
+
+public:
+ NTSTATUS EventHandler_PinCapsChange
+ (
+ _In_ PPCEVENT_REQUEST EventRequest
+ );
+
+ NTSTATUS ValidateStreamCreate
+ (
+ _In_ ULONG _Pin,
+ _In_ BOOLEAN _Capture
+ );
+
+ NTSTATUS StreamCreated
+ (
+ _In_ ULONG _Pin,
+ _In_ PCMiniportWaveRTStream _Stream
+ );
+
+ NTSTATUS StreamClosed
+ (
+ _In_ ULONG _Pin,
+ _In_ PCMiniportWaveRTStream _Stream
+ );
+
+ NTSTATUS IsFormatSupported
+ (
+ _In_ ULONG _ulPin,
+ _In_ BOOLEAN _bCapture,
+ _In_ PKSDATAFORMAT _pDataFormat
+ );
+
+ static NTSTATUS GetAttributesFromAttributeList
+ (
+ _In_ const KSMULTIPLE_ITEM *_pAttributes,
+ _In_ size_t _Size,
+ _Out_ GUID* _pSignalProcessingMode
+ );
+
+protected:
+ NTSTATUS UpdateDrmRights
+ (
+ void
+ );
+
+public:
+ DECLARE_STD_UNKNOWN();
+
+#pragma code_seg("PAGE")
+ CMiniportWaveRT(
+ _In_ PUNKNOWN UnknownAdapter,
+ _In_ PENDPOINT_MINIPAIR MiniportPair,
+ _In_opt_ PVOID DeviceContext
+ )
+ :CUnknown(0),
+ m_ulMaxSystemStreams(0),
+ m_DeviceType(MiniportPair->DeviceType),
+ m_DeviceContext(DeviceContext),
+ m_DeviceMaxChannels(MiniportPair->DeviceMaxChannels),
+ m_DeviceFormatsAndModes(MiniportPair->PinDeviceFormatsAndModes),
+ m_DeviceFormatsAndModesCount(MiniportPair->PinDeviceFormatsAndModesCount),
+ m_DeviceFlags(MiniportPair->DeviceFlags),
+ m_pMiniportPair(MiniportPair)
+ {
+ PAGED_CODE();
+
+ m_pAdapterCommon = (PADAPTERCOMMON)UnknownAdapter; // weak ref.
+
+ if (MiniportPair->WaveDescriptor)
+ {
+ RtlCopyMemory(&m_FilterDesc, MiniportPair->WaveDescriptor, sizeof(m_FilterDesc));
+
+ //
+ // Get the max # of pin instances.
+ //
+ if (IsRenderDevice())
+ {
+ if (m_FilterDesc.PinCount > KSPIN_WAVE_RENDER2_SOURCE)
+ {
+ m_ulMaxSystemStreams = m_FilterDesc.Pins[KSPIN_WAVE_RENDER2_SINK_SYSTEM].MaxFilterInstanceCount;
+ m_ulMaxLoopbackStreams = m_FilterDesc.Pins[KSPIN_WAVE_RENDER2_SINK_LOOPBACK].MaxFilterInstanceCount;
+ }
+ else if(m_FilterDesc.PinCount > KSPIN_WAVE_RENDER3_SOURCE)
+ {
+ m_ulMaxSystemStreams = m_FilterDesc.Pins[KSPIN_WAVE_RENDER3_SINK_SYSTEM].MaxFilterInstanceCount;
+ }
+ }
+ else
+ {
+ //
+ // capture bridge pin comes first in the enumeration
+ //
+ if (m_FilterDesc.PinCount > KSPIN_WAVEIN_HOST)
+ {
+ m_ulMaxSystemStreams = m_FilterDesc.Pins[KSPIN_WAVEIN_HOST].MaxFilterInstanceCount;
+ }
+ }
+ }
+
+ KeInitializeSpinLock(&m_DeviceFormatsAndModesLock);
+ m_DeviceFormatsAndModesIrql = PASSIVE_LEVEL;
+ }
+
+#pragma code_seg()
+
+ ~CMiniportWaveRT();
+
+ IMP_IMiniportWaveRT;
+ IMP_IMiniportAudioSignalProcessing;
+
+ // Friends
+ friend class CMiniportWaveRTStream;
+ friend class CMiniportTopologySimpleAudioSample;
+
+ friend NTSTATUS PropertyHandler_WaveFilter
+ (
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+ );
+
+public:
+public:
+ NTSTATUS PropertyHandlerProposedFormat
+ (
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+ );
+
+ NTSTATUS PropertyHandlerProposedFormat2
+
+ (
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+ );
+
+ PADAPTERCOMMON GetAdapterCommObj()
+ {
+ return m_pAdapterCommon;
+ };
+#pragma code_seg()
+
+ //---------------------------------------------------------------------------------------------------------
+ // volume
+ //---------------------------------------------------------------------------------------------------------
+ NTSTATUS GetVolumeChannelCount
+ (
+ _Out_ UINT32* pulChannelCount
+ );
+
+ NTSTATUS GetVolumeSteppings
+ (
+ _Out_writes_bytes_(_ui32DataSize) PKSPROPERTY_STEPPING_LONG _pKsPropStepLong,
+ _In_ UINT32 _ui32DataSize
+ );
+
+ NTSTATUS GetChannelVolume
+ (
+ _In_ UINT32 _uiChannel,
+ _Out_ LONG* _pVolume
+ );
+
+ NTSTATUS SetChannelVolume
+ (
+ _In_ UINT32 _uiChannel,
+ _In_ LONG _Volume
+ );
+
+ //-----------------------------------------------------------------------------
+ // mute
+ //-----------------------------------------------------------------------------
+ NTSTATUS GetMuteChannelCount
+ (
+ _Out_ UINT32* pulChannelCount
+ );
+
+ NTSTATUS GetMuteSteppings
+ (
+ _Out_writes_bytes_(_ui32DataSize) PKSPROPERTY_STEPPING_LONG _pKsPropStepLong,
+ _In_ UINT32 _ui32DataSize
+ );
+
+ NTSTATUS GetChannelMute
+ (
+ _In_ UINT32 _uiChannel,
+ _Out_ BOOL* _pbMute
+ );
+
+ NTSTATUS SetChannelMute
+ (
+ _In_ UINT32 _uiChannel,
+ _In_ BOOL _bMute
+ );
+
+private:
+ _IRQL_raises_(DISPATCH_LEVEL)
+ _Acquires_lock_(m_DeviceFormatsAndModesLock)
+ _Requires_lock_not_held_(m_DeviceFormatsAndModesLock)
+ _IRQL_saves_global_(SpinLock, m_DeviceFormatsAndModesIrql)
+ VOID AcquireFormatsAndModesLock();
+
+ _Releases_lock_(m_DeviceFormatsAndModesLock)
+ _Requires_lock_held_(m_DeviceFormatsAndModesLock)
+ _IRQL_restores_global_(SpinLock, m_DeviceFormatsAndModesIrql)
+ VOID ReleaseFormatsAndModesLock();
+
+ _Post_satisfies_(return > 0)
+ ULONG GetPinSupportedDeviceFormats(_In_ ULONG PinId, _Outptr_opt_result_buffer_(return) KSDATAFORMAT_WAVEFORMATEXTENSIBLE **ppFormats);
+
+ _Success_(return != 0)
+ ULONG GetPinSupportedDeviceModes(_In_ ULONG PinId, _Outptr_opt_result_buffer_(return) _On_failure_(_Deref_post_null_) MODE_AND_DEFAULT_FORMAT **ppModes);
+
+#pragma code_seg()
+
+protected:
+#pragma code_seg()
+ BOOL IsRenderDevice()
+ {
+ return m_DeviceType == eSpeakerDevice ? TRUE : FALSE;
+ }
+
+ BOOL IsSystemRenderPin(ULONG nPinId);
+
+ BOOL IsSystemCapturePin(ULONG nPinId);
+
+ BOOL IsBridgePin(ULONG nPinId);
+
+ // These three pins are the pins used by the audio engine for host, loopback, and offload.
+ ULONG GetSystemPinId()
+ {
+ ASSERT(IsRenderDevice());
+ return KSPIN_WAVE_RENDER2_SINK_SYSTEM;
+ }
+};
+
+typedef CMiniportWaveRT *PCMiniportWaveRT;
+
+#endif // _SIMPLEAUDIOSAMPLE_MINWAVERT_H_
diff --git a/audio/simpleaudiosample/Source/Main/minwavertstream.cpp b/audio/simpleaudiosample/Source/Main/minwavertstream.cpp
new file mode 100644
index 00000000..27289a0e
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/minwavertstream.cpp
@@ -0,0 +1,1644 @@
+#include "definitions.h"
+#include <limits.h>
+#include <ks.h>
+#include "endpoints.h"
+#include "minwavert.h"
+#include "minwavertstream.h"
+#define MINWAVERTSTREAM_POOLTAG 'SRWM'
+
+#pragma warning (disable : 4127)
+
+//=============================================================================
+// CMiniportWaveRTStream
+//=============================================================================
+
+//=============================================================================
+#pragma code_seg("PAGE")
+CMiniportWaveRTStream::~CMiniportWaveRTStream
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Destructor for wavertstream
+
+Arguments:
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+ if (NULL != m_pMiniport)
+ {
+
+ if (m_bUnregisterStream)
+ {
+ m_pMiniport->StreamClosed(m_ulPin, this);
+ m_bUnregisterStream = FALSE;
+ }
+
+ m_pMiniport->Release();
+ m_pMiniport = NULL;
+ }
+
+ if (m_pDpc)
+ {
+ ExFreePoolWithTag( m_pDpc, MINWAVERTSTREAM_POOLTAG );
+ m_pDpc = NULL;
+ }
+
+ if (m_pTimer)
+ {
+ ExFreePoolWithTag( m_pTimer, MINWAVERTSTREAM_POOLTAG );
+ m_pTimer = NULL;
+ }
+
+ if (m_pbMuted)
+ {
+ ExFreePoolWithTag( m_pbMuted, MINWAVERTSTREAM_POOLTAG );
+ m_pbMuted = NULL;
+ }
+
+ if (m_plVolumeLevel)
+ {
+ ExFreePoolWithTag( m_plVolumeLevel, MINWAVERTSTREAM_POOLTAG );
+ m_plVolumeLevel = NULL;
+ }
+
+ if (m_plPeakMeter)
+ {
+ ExFreePoolWithTag( m_plPeakMeter, MINWAVERTSTREAM_POOLTAG );
+ m_plPeakMeter = NULL;
+ }
+
+ if (m_pWfExt)
+ {
+ ExFreePoolWithTag( m_pWfExt, MINWAVERTSTREAM_POOLTAG );
+ m_pWfExt = NULL;
+ }
+ if (m_pNotificationTimer)
+ {
+ ExDeleteTimer
+ (
+ m_pNotificationTimer,
+ TRUE, // Cancel the timer if it is currently set.
+ TRUE, // Wait for the timer to finish expiring and for any callback to a ExTimerCallback routine to finish.
+ NULL
+ );
+ }
+
+ // Since we just cancelled the notification timer, wait for all queued
+ // DPCs to complete before we free the notification DPC.
+ //
+ KeFlushQueuedDpcs();
+
+ DPF_ENTER(("[CMiniportWaveRTStream::~CMiniportWaveRTStream]"));
+} // ~CMiniportWaveRTStream
+
+//=============================================================================
+#pragma code_seg("PAGE")
+
+NTSTATUS CMiniportWaveRTStream::ReadRegistrySettings()
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus;
+ UNICODE_STRING parametersPath;
+
+ RTL_QUERY_REGISTRY_TABLE paramTable[] = {
+ // QueryRoutine Flags Name EntryContext DefaultType DefaultData DefaultLength
+ { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK, L"HostCaptureToneFrequency", &m_ulHostCaptureToneFrequency, (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD, &m_ulHostCaptureToneFrequency, sizeof(DWORD) },
+ { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK, L"HostCaptureToneAmplitude", &m_dwHostCaptureToneAmplitude, (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD, &m_dwHostCaptureToneAmplitude, sizeof(DWORD) },
+ { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK, L"HostCaptureToneDCOffset", &m_dwHostCaptureToneDCOffset, (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD, &m_dwHostCaptureToneDCOffset, sizeof(DWORD) },
+ { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK, L"HostCaptureToneInitialPhase", &m_dwHostCaptureToneInitialPhase, (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD, &m_dwHostCaptureToneInitialPhase, sizeof(DWORD) },
+ { NULL, 0, NULL, NULL, 0, NULL, 0 }
+ };
+
+ RtlInitUnicodeString(&parametersPath, NULL);
+
+ // The sizeof(WCHAR) is added to the maximum length, for allowing a space for null termination of the string.
+ parametersPath.MaximumLength =
+ g_RegistryPath.Length + sizeof(L"\\Parameters") + sizeof(WCHAR);
+
+ parametersPath.Buffer = (PWCH)ExAllocatePool2(POOL_FLAG_PAGED, parametersPath.MaximumLength, MINWAVERT_POOLTAG);
+ if (parametersPath.Buffer == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlAppendUnicodeToString(&parametersPath, g_RegistryPath.Buffer);
+ RtlAppendUnicodeToString(&parametersPath, L"\\Parameters");
+
+ ntStatus = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
+ parametersPath.Buffer,
+ &paramTable[0],
+ NULL,
+ NULL
+ );
+
+ ExFreePool(parametersPath.Buffer);
+
+ return ntStatus;
+}
+
+NTSTATUS
+CMiniportWaveRTStream::Init
+(
+ _In_ PCMiniportWaveRT Miniport_,
+ _In_ PPORTWAVERTSTREAM PortStream_,
+ _In_ ULONG Pin_,
+ _In_ BOOLEAN Capture_,
+ _In_ PKSDATAFORMAT DataFormat_,
+ _In_ GUID SignalProcessingMode
+)
+/*++
+
+Routine Description:
+
+ Initializes the stream object.
+
+Arguments:
+
+ Miniport_ -
+
+ Pin_ -
+
+ DataFormat -
+
+ SignalProcessingMode - The driver uses the signalProcessingMode to configure
+ driver and/or hardware specific signal processing to be applied to this new
+ stream.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ PWAVEFORMATEX pWfEx = NULL;
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ m_pMiniport = NULL;
+ m_ulPin = 0;
+ m_bUnregisterStream = FALSE;
+ m_bCapture = FALSE;
+ m_ulDmaBufferSize = 0;
+ m_pDmaBuffer = NULL;
+ m_ulNotificationsPerBuffer = 0;
+ m_KsState = KSSTATE_STOP;
+ m_pTimer = NULL;
+ m_pDpc = NULL;
+ m_llPacketCounter = 0;
+ m_ullPlayPosition = 0;
+ m_ullWritePosition = 0;
+ m_ullDmaTimeStamp = 0;
+ m_hnsElapsedTimeCarryForward = 0;
+ m_ullLastDPCTimeStamp = 0;
+ m_hnsDPCTimeCarryForward = 0;
+ m_ulDmaMovementRate = 0;
+ m_byteDisplacementCarryForward = 0;
+ m_bLfxEnabled = FALSE;
+ m_pbMuted = NULL;
+ m_plVolumeLevel = NULL;
+ m_plPeakMeter = NULL;
+ m_pWfExt = NULL;
+ m_ullLinearPosition = 0;
+ m_ullPresentationPosition = 0;
+ m_ulContentId = 0;
+ m_ulCurrentWritePosition = 0;
+ m_ulLastOsReadPacket = ULONG_MAX;
+ m_ulLastOsWritePacket = ULONG_MAX;
+ m_IsCurrentWritePositionUpdated = 0;
+ m_SignalProcessingMode = SignalProcessingMode;
+ m_bEoSReceived = FALSE;
+ m_bLastBufferRendered = FALSE;
+
+ m_ulHostCaptureToneFrequency = IsEqualGUID(SignalProcessingMode, AUDIO_SIGNALPROCESSINGMODE_RAW) ? 1000 : 2000;
+ m_dwHostCaptureToneAmplitude = 50;
+ m_dwHostCaptureToneDCOffset = 0;
+ m_dwHostCaptureToneInitialPhase = 0;
+
+ m_pPortStream = PortStream_;
+ InitializeListHead(&m_NotificationList);
+ m_ulNotificationIntervalMs = 0;
+
+ // Initialize the spinlock to synchronize position updates
+ KeInitializeSpinLock(&m_PositionSpinLock);
+
+ m_pNotificationTimer = ExAllocateTimer(
+ TimerNotifyRT,
+ this,
+ EX_TIMER_HIGH_RESOLUTION
+ );
+ if (!m_pNotificationTimer)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ pWfEx = GetWaveFormatEx(DataFormat_);
+ if (NULL == pWfEx)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ m_pMiniport = reinterpret_cast<CMiniportWaveRT*>(Miniport_);
+ if (m_pMiniport == NULL)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+ m_pMiniport->AddRef();
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return ntStatus;
+ }
+ m_ulPin = Pin_;
+ m_bCapture = Capture_;
+ m_ulDmaMovementRate = pWfEx->nAvgBytesPerSec;
+
+ m_pDpc = (PRKDPC)ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(KDPC), MINWAVERTSTREAM_POOLTAG);
+ if (!m_pDpc)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ m_pWfExt = (PWAVEFORMATEXTENSIBLE)ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(WAVEFORMATEX) + pWfEx->cbSize, MINWAVERTSTREAM_POOLTAG);
+ if (m_pWfExt == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ RtlCopyMemory(m_pWfExt, pWfEx, sizeof(WAVEFORMATEX) + pWfEx->cbSize);
+
+ m_pbMuted = (PBOOL)ExAllocatePool2(POOL_FLAG_NON_PAGED, m_pWfExt->Format.nChannels * sizeof(BOOL), MINWAVERTSTREAM_POOLTAG);
+ if (m_pbMuted == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ m_plVolumeLevel = (PLONG)ExAllocatePool2(POOL_FLAG_NON_PAGED, m_pWfExt->Format.nChannels * sizeof(LONG), MINWAVERTSTREAM_POOLTAG);
+ if (m_plVolumeLevel == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ m_plPeakMeter = (PLONG)ExAllocatePool2(POOL_FLAG_NON_PAGED, m_pWfExt->Format.nChannels * sizeof(LONG), MINWAVERTSTREAM_POOLTAG);
+ if (m_plPeakMeter == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if (m_bCapture)
+ {
+ ReadRegistrySettings();
+ DWORD toneFrequency = 0;
+ DWORD toneAmplitude = 0;
+ DWORD toneDCOffset = 0;
+ DWORD toneInitialPhase = 0;
+
+ double toneAmplitudeDouble = 0;
+ double toneDCOffsetDouble = 0;
+ double toneInitialPhaseDouble = 0;
+
+ toneFrequency = m_ulHostCaptureToneFrequency;
+ toneAmplitude = m_dwHostCaptureToneAmplitude;
+ toneDCOffset = m_dwHostCaptureToneDCOffset;
+ toneInitialPhase = m_dwHostCaptureToneInitialPhase;
+
+ if (labs(toneAmplitude) > 100)
+ {
+ toneAmplitude = toneAmplitude > 0 ? 100 : -100;
+ }
+
+ if (labs(toneDCOffset) > 100)
+ {
+ toneDCOffset = toneDCOffset > 0 ? 100 : -100;
+ }
+
+ DWORD abssum = labs(toneAmplitude) + labs(toneDCOffset);
+
+ if (abssum > 100)
+ {
+ toneAmplitudeDouble = ((double)toneAmplitude) / abssum;
+ toneDCOffsetDouble = ((double)toneDCOffset) / abssum;
+ }
+ else
+ {
+ toneAmplitudeDouble = ((double)toneAmplitude) / 100.0;
+ toneDCOffsetDouble = ((double)toneDCOffset) / 100.0;
+ }
+
+ if (labs(toneInitialPhase) > 31416)
+ {
+ toneInitialPhase = toneInitialPhase > 0 ? 31416 : -31416;
+ }
+
+ toneInitialPhaseDouble = (double)toneInitialPhase / 10000;
+
+ ntStatus = m_ToneGenerator.Init(toneFrequency, toneAmplitudeDouble, toneDCOffsetDouble, toneInitialPhaseDouble, m_pWfExt);
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return ntStatus;
+ }
+ }
+ else if (!g_DoNotCreateDataFiles)
+ {
+ //
+ // Create an output file for the render data.
+ //
+ DPF(D_TERSE, ("SaveData %p", &m_SaveData));
+ ntStatus = m_SaveData.SetDataFormat(DataFormat_);
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = m_SaveData.Initialize();
+ }
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return ntStatus;
+ }
+ }
+
+ //
+ // Register this stream.
+ //
+ ntStatus = m_pMiniport->StreamCreated(m_ulPin, this);
+ if (NT_SUCCESS(ntStatus))
+ {
+ m_bUnregisterStream = TRUE;
+ }
+
+ return ntStatus;
+} // Init
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CMiniportWaveRTStream::NonDelegatingQueryInterface
+(
+ _In_ REFIID Interface,
+ _COM_Outptr_ PVOID * Object
+)
+/*++
+
+Routine Description:
+
+ QueryInterface
+
+Arguments:
+
+ Interface - GUID
+
+ Object - interface pointer to be returned
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(Object);
+
+ if (IsEqualGUIDAligned(Interface, IID_IUnknown))
+ {
+ *Object = PVOID(PUNKNOWN(PMINIPORTWAVERTSTREAM(this)));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveRTStream))
+ {
+ *Object = PVOID(PMINIPORTWAVERTSTREAM(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveRTStreamNotification))
+ {
+ *Object = PVOID(PMINIPORTWAVERTSTREAMNOTIFICATION(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveRTInputStream) && (this->m_bCapture))
+ {
+ // This interface is supported only on capture streams
+ *Object = PVOID(PMINIPORTWAVERTINPUTSTREAM(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveRTOutputStream))
+ {
+ // This interface is supported only on host render streams
+ *Object = PVOID(PMINIPORTWAVERTOUTPUTSTREAM(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IDrmAudioStream))
+ {
+ *Object = (PVOID)(IDrmAudioStream*)this;
+ }
+ else
+ {
+ *Object = NULL;
+ }
+
+ if (*Object)
+ {
+ PUNKNOWN(*Object)->AddRef();
+ return STATUS_SUCCESS;
+ }
+
+ return STATUS_INVALID_PARAMETER;
+} // NonDelegatingQueryInterface
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS CMiniportWaveRTStream::AllocateBufferWithNotification
+(
+ _In_ ULONG NotificationCount_,
+ _In_ ULONG RequestedSize_,
+ _Out_ PMDL *AudioBufferMdl_,
+ _Out_ ULONG *ActualSize_,
+ _Out_ ULONG *OffsetFromFirstPage_,
+ _Out_ MEMORY_CACHING_TYPE *CacheType_
+)
+{
+ PAGED_CODE();
+
+ ULONG ulBufferDurationMs = 0;
+
+ if ( (0 == RequestedSize_) || (RequestedSize_ < m_pWfExt->Format.nBlockAlign) )
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ if ((NotificationCount_ == 0) || (RequestedSize_ % NotificationCount_ != 0))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ RequestedSize_ -= RequestedSize_ % (m_pWfExt->Format.nBlockAlign);
+
+ if (!m_bCapture && (!g_DoNotCreateDataFiles))
+ {
+ NTSTATUS ntStatus;
+
+ // Simple Audio Sample uses following buffer to hold data before writing to a file.
+ // Allocating larger buffer will reduce File I/O operations.
+ ntStatus = m_SaveData.SetMaxWriteSize(RequestedSize_ * 4);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ return ntStatus;
+ }
+ }
+
+ PHYSICAL_ADDRESS highAddress;
+ highAddress.HighPart = 0;
+ highAddress.LowPart = MAXULONG;
+
+ PMDL pBufferMdl = m_pPortStream->AllocatePagesForMdl (highAddress, RequestedSize_);
+
+ if (NULL == pBufferMdl)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ // From MSDN:
+ // "Since the Windows audio stack does not support a mechanism to express memory access
+ // alignment requirements for buffers, audio drivers must select a caching type for mapped
+ // memory buffers that does not impose platform-specific alignment requirements. In other
+ // words, the caching type used by the audio driver for mapped memory buffers, must not make
+ // assumptions about the memory alignment requirements for any specific platform.
+ //
+ // This method maps the physical memory pages in the MDL into kernel-mode virtual memory.
+ // Typically, the miniport driver calls this method if it requires software access to the
+ // scatter-gather list for an audio buffer. In this case, the storage for the scatter-gather
+ // list must have been allocated by the IPortWaveRTStream::AllocatePagesForMdl or
+ // IPortWaveRTStream::AllocateContiguousPagesForMdl method.
+ //
+ // A WaveRT miniport driver should not require software access to the audio buffer itself."
+ //
+ m_pDmaBuffer = (BYTE*)m_pPortStream->MapAllocatedPages(pBufferMdl, MmCached);
+ m_ulNotificationsPerBuffer = NotificationCount_;
+ m_ulDmaBufferSize = RequestedSize_;
+ ulBufferDurationMs = (RequestedSize_ * 1000) / m_ulDmaMovementRate;
+ m_ulNotificationIntervalMs = ulBufferDurationMs / NotificationCount_;
+
+ *AudioBufferMdl_ = pBufferMdl;
+ *ActualSize_ = RequestedSize_;
+ *OffsetFromFirstPage_ = 0;
+ *CacheType_ = MmCached;
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+VOID CMiniportWaveRTStream::FreeBufferWithNotification
+(
+ _In_ PMDL Mdl_,
+ _In_ ULONG Size_
+)
+{
+ UNREFERENCED_PARAMETER(Size_);
+
+ PAGED_CODE();
+
+ if (Mdl_ != NULL)
+ {
+ if (m_pDmaBuffer != NULL)
+ {
+ m_pPortStream->UnmapAllocatedPages(m_pDmaBuffer, Mdl_);
+ m_pDmaBuffer = NULL;
+ }
+
+ m_pPortStream->FreePagesFromMdl(Mdl_);
+ }
+
+ m_ulDmaBufferSize = 0;
+ m_ulNotificationsPerBuffer = 0;
+
+ return;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS CMiniportWaveRTStream::RegisterNotificationEvent
+(
+ _In_ PKEVENT NotificationEvent_
+)
+{
+ UNREFERENCED_PARAMETER(NotificationEvent_);
+
+ PAGED_CODE();
+
+ NotificationListEntry *nleNew = (NotificationListEntry*)ExAllocatePool2(
+ POOL_FLAG_NON_PAGED,
+ sizeof(NotificationListEntry),
+ MINWAVERTSTREAM_POOLTAG);
+ if (NULL == nleNew)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ nleNew->NotificationEvent = NotificationEvent_;
+
+ // Fail if the notification event already exists in our list.
+ if (!IsListEmpty(&m_NotificationList))
+ {
+ PLIST_ENTRY leCurrent = m_NotificationList.Flink;
+ while (leCurrent != &m_NotificationList)
+ {
+ NotificationListEntry* nleCurrent = CONTAINING_RECORD( leCurrent, NotificationListEntry, ListEntry);
+ if (nleCurrent->NotificationEvent == NotificationEvent_)
+ {
+ ExFreePoolWithTag( nleNew, MINWAVERTSTREAM_POOLTAG );
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ leCurrent = leCurrent->Flink;
+ }
+ }
+
+ InsertTailList(&m_NotificationList, &(nleNew->ListEntry));
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS CMiniportWaveRTStream::UnregisterNotificationEvent
+(
+ _In_ PKEVENT NotificationEvent_
+)
+{
+ UNREFERENCED_PARAMETER(NotificationEvent_);
+
+ PAGED_CODE();
+
+ if (!IsListEmpty(&m_NotificationList))
+ {
+ PLIST_ENTRY leCurrent = m_NotificationList.Flink;
+ while (leCurrent != &m_NotificationList)
+ {
+ NotificationListEntry* nleCurrent = CONTAINING_RECORD( leCurrent, NotificationListEntry, ListEntry);
+ if (nleCurrent->NotificationEvent == NotificationEvent_)
+ {
+ RemoveEntryList( leCurrent );
+ ExFreePoolWithTag( nleCurrent, MINWAVERTSTREAM_POOLTAG );
+ return STATUS_SUCCESS;
+ }
+
+ leCurrent = leCurrent->Flink;
+ }
+ }
+
+ return STATUS_NOT_FOUND;
+}
+
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS CMiniportWaveRTStream::GetClockRegister
+(
+ _Out_ PKSRTAUDIO_HWREGISTER Register_
+)
+{
+ UNREFERENCED_PARAMETER(Register_);
+
+ PAGED_CODE();
+
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS CMiniportWaveRTStream::GetPositionRegister
+(
+ _Out_ PKSRTAUDIO_HWREGISTER Register_
+)
+{
+ UNREFERENCED_PARAMETER(Register_);
+
+ PAGED_CODE();
+
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+VOID CMiniportWaveRTStream::GetHWLatency
+(
+ _Out_ PKSRTAUDIO_HWLATENCY Latency_
+)
+{
+ PAGED_CODE();
+
+ ASSERT(Latency_);
+
+ Latency_->ChipsetDelay = 0;
+ Latency_->CodecDelay = 0;
+ Latency_->FifoSize = 0;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+VOID CMiniportWaveRTStream::FreeAudioBuffer
+(
+_In_opt_ PMDL Mdl_,
+_In_ ULONG Size_
+)
+{
+ UNREFERENCED_PARAMETER(Size_);
+
+ PAGED_CODE();
+
+ if (Mdl_ != NULL)
+ {
+ if (m_pDmaBuffer != NULL)
+ {
+ m_pPortStream->UnmapAllocatedPages(m_pDmaBuffer, Mdl_);
+ m_pDmaBuffer = NULL;
+ }
+
+ m_pPortStream->FreePagesFromMdl(Mdl_);
+ }
+
+ m_ulDmaBufferSize = 0;
+ m_ulNotificationsPerBuffer = 0;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS CMiniportWaveRTStream::AllocateAudioBuffer
+(
+_In_ ULONG RequestedSize_,
+_Out_ PMDL *AudioBufferMdl_,
+_Out_ ULONG *ActualSize_,
+_Out_ ULONG *OffsetFromFirstPage_,
+_Out_ MEMORY_CACHING_TYPE *CacheType_
+)
+{
+ PAGED_CODE();
+
+ if ((0 == RequestedSize_) || (RequestedSize_ < m_pWfExt->Format.nBlockAlign))
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ RequestedSize_ -= RequestedSize_ % (m_pWfExt->Format.nBlockAlign);
+
+ PHYSICAL_ADDRESS highAddress;
+ highAddress.HighPart = 0;
+ highAddress.LowPart = MAXULONG;
+
+ PMDL pBufferMdl = m_pPortStream->AllocatePagesForMdl(highAddress, RequestedSize_);
+
+ if (NULL == pBufferMdl)
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ // From MSDN:
+ // "Since the Windows audio stack does not support a mechanism to express memory access
+ // alignment requirements for buffers, audio drivers must select a caching type for mapped
+ // memory buffers that does not impose platform-specific alignment requirements. In other
+ // words, the caching type used by the audio driver for mapped memory buffers, must not make
+ // assumptions about the memory alignment requirements for any specific platform.
+ //
+ // This method maps the physical memory pages in the MDL into kernel-mode virtual memory.
+ // Typically, the miniport driver calls this method if it requires software access to the
+ // scatter-gather list for an audio buffer. In this case, the storage for the scatter-gather
+ // list must have been allocated by the IPortWaveRTStream::AllocatePagesForMdl or
+ // IPortWaveRTStream::AllocateContiguousPagesForMdl method.
+ //
+ // A WaveRT miniport driver should not require software access to the audio buffer itself."
+ //
+ m_pDmaBuffer = (BYTE*)m_pPortStream->MapAllocatedPages(pBufferMdl, MmCached);
+
+ m_ulDmaBufferSize = RequestedSize_;
+ m_ulNotificationsPerBuffer = 0;
+
+ *AudioBufferMdl_ = pBufferMdl;
+ *ActualSize_ = RequestedSize_;
+ *OffsetFromFirstPage_ = 0;
+ *CacheType_ = MmCached;
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg()
+NTSTATUS CMiniportWaveRTStream::GetPosition
+(
+ _Out_ KSAUDIO_POSITION *Position_
+)
+{
+ NTSTATUS ntStatus;
+
+ KIRQL oldIrql;
+ KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql);
+
+ if (m_KsState == KSSTATE_RUN)
+ {
+ //
+ // Get the current time and update position.
+ //
+ LARGE_INTEGER ilQPC = KeQueryPerformanceCounter(NULL);
+ UpdatePosition(ilQPC);
+ }
+
+ Position_->PlayOffset = m_ullPlayPosition;
+ Position_->WriteOffset = m_ullWritePosition;
+
+ KeReleaseSpinLock(&m_PositionSpinLock, oldIrql);
+
+ ntStatus = STATUS_SUCCESS;
+
+ return ntStatus;
+}
+
+//=============================================================================
+// CMiniportWaveRTStream::GetReadPacket
+//
+// Returns information about the next packet for the OS to read.
+//
+// Return value
+//
+// Returns STATUS_DEVICE_NOT_READY if no new packets are available.
+//
+// IRQL - PASSIVE_LEVEL
+//
+// Remarks
+// Although called at passive level, this routine is non-paged code because
+// it is called in the streaming path where page faults should be avoided.
+//
+// ISSUE-2014/10/4 Will this work correctly across pause/play?
+#pragma code_seg()
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS CMiniportWaveRTStream::GetReadPacket
+(
+ _Out_ ULONG* PacketNumber,
+ _Out_ DWORD* Flags,
+ _Out_ ULONG64* PerformanceCounterValue,
+ _Out_ BOOL* MoreData
+)
+{
+ ULONG availablePacketNumber;
+ ULONG droppedPackets;
+
+ // The call must be from event driven mode
+ if (m_ulNotificationsPerBuffer == 0)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ *Flags = 0;
+
+ if (m_KsState < KSSTATE_PAUSE)
+ {
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ KIRQL oldIrql;
+ KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql);
+
+ LONGLONG packetCounter = m_llPacketCounter;
+ ULONGLONG ullLinearPosition = m_ullLinearPosition;
+ ULONGLONG hnsElapsedTimeCarryForward = m_hnsElapsedTimeCarryForward;
+ ULONGLONG ullDmaTimeStamp = m_ullDmaTimeStamp;
+
+ KeReleaseSpinLock(&m_PositionSpinLock, oldIrql);
+
+ // The 0-based number of the last completed packet
+ // FUTURE-2014/10/27 Update to allow different numbers of packets per WaveRT buffer
+ availablePacketNumber = LODWORD(packetCounter - 1); // Note this might be ULONG_MAX if called during the first packet
+
+ // If no new packets are available...
+ if (availablePacketNumber == m_ulLastOsReadPacket)
+ {
+ return STATUS_DEVICE_NOT_READY;
+ }
+
+ // If more than one packet has transferred since the last packet read by
+ // the OS, then those were dropped. That is, a glitch occurred.
+ droppedPackets = availablePacketNumber - m_ulLastOsReadPacket - 1;
+ if (droppedPackets > 0)
+ {
+ // Trace a glitch
+ }
+
+ // Return next packet number to be read
+ *PacketNumber = availablePacketNumber;
+
+ // Compute and return timestamp corresponding to the end of the available packet. In a real hardware
+ // driver, the timestamp would be computed in a driver and hardware specific manner. In this sample
+ // driver, it is extrapolated from the sample driver's internal simulated position correlation
+ // [m_ullLinearPosition @ m_ullDmaTimeStamp] and the sample's internal 64-bit packet counter, subtracting
+ // 1 from the packet counter to compute the time at the start of that last completed packet.
+ ULONGLONG linearPositionOfAvailablePacket = packetCounter * (m_ulDmaBufferSize / m_ulNotificationsPerBuffer);
+ // Need to divide by (1000 * 10000 because m_ulDmaMovementRate is average bytes per sec
+ ULONGLONG carryForwardBytes = (hnsElapsedTimeCarryForward * m_ulDmaMovementRate) / 10000000;
+ ULONGLONG deltaLinearPosition = ullLinearPosition + carryForwardBytes - linearPositionOfAvailablePacket;
+ ULONGLONG deltaTimeInHns = deltaLinearPosition * 10000000 / m_ulDmaMovementRate;
+ ULONGLONG timeOfAvailablePacketInHns = ullDmaTimeStamp - deltaTimeInHns;
+ ULONGLONG timeOfAvailablePacketInQpc = timeOfAvailablePacketInHns * m_ullPerformanceCounterFrequency.QuadPart / 10000000;
+
+ *PerformanceCounterValue = timeOfAvailablePacketInQpc;
+
+ // No flags are defined yet
+ *Flags = 0;
+
+ // This sample does not internally buffer data so there is never more data
+ // than revealed by the results from this routine.
+ *MoreData = FALSE;
+
+ // Update the last packet read by the OS
+ m_ulLastOsReadPacket = availablePacketNumber;
+
+ return STATUS_SUCCESS;
+}
+
+#pragma code_seg()
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS CMiniportWaveRTStream::SetWritePacket
+(
+ _In_ ULONG PacketNumber,
+ _In_ DWORD Flags,
+ _In_ ULONG EosPacketLength
+)
+{
+ UNREFERENCED_PARAMETER(EosPacketLength);
+ NTSTATUS ntStatus;
+
+ // The call must be from event driven mode
+ if (m_ulNotificationsPerBuffer == 0)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ ULONG oldLastOsWritePacket = m_ulLastOsWritePacket;
+
+ // This function should not be called once EoS has been set.
+ if (m_bEoSReceived)
+ {
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ KIRQL oldIrql;
+ KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql);
+ // 1-based count of completed packets, 0-based packet number of current packet
+ LONGLONG currentPacket = m_llPacketCounter;
+ KeReleaseSpinLock(&m_PositionSpinLock, oldIrql);
+
+ // If not running, the current packet hasn't actually started transfering so OS should be writing
+ // to the current packet. If running, then the current packing is already transfering to hardware
+ // so the OS should write the packet after the current packet.
+ ULONG expectedPacket = LODWORD(currentPacket);
+ if (m_KsState == KSSTATE_RUN)
+ {
+ expectedPacket++;
+ }
+
+ // Check if OS PacketNumber is behind or too far ahead of current packet
+ LONG deltaFromExpectedPacket = PacketNumber - expectedPacket; // Modulo arithemetic
+ if (deltaFromExpectedPacket < 0)
+ {
+ return STATUS_DATA_LATE_ERROR;
+ }
+ else if (deltaFromExpectedPacket > 0)
+ {
+ return STATUS_DATA_OVERRUN;
+ }
+
+ ULONG packetSize = (m_ulDmaBufferSize / m_ulNotificationsPerBuffer);
+ ULONG packetIndex = PacketNumber % m_ulNotificationsPerBuffer;
+ ULONG ulCurrentWritePosition = packetIndex * packetSize;
+
+ // Check if EOS flag was passed
+ if (Flags & KSSTREAM_HEADER_OPTIONSF_ENDOFSTREAM)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ m_ulLastOsWritePacket = PacketNumber;
+
+ // This function sets the current write position to the specified byte in the DMA buffer.
+ // Will check if the write position is smaller than the DMA buffer size.
+ // Will not return an error when the passed in parameter is 0.
+ // Will also check if this function was called with the same write position(in event mode only)
+ // Underruning will also be checked via timer mechanism
+ KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql);
+ ntStatus = SetCurrentWritePositionInternal(ulCurrentWritePosition);
+ KeReleaseSpinLock(&m_PositionSpinLock, oldIrql);
+ }
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ m_ulLastOsWritePacket = oldLastOsWritePacket;
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg()
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS CMiniportWaveRTStream::GetOutputStreamPresentationPosition
+(
+ _Out_ KSAUDIO_PRESENTATION_POSITION *pPresentationPosition
+)
+{
+ ASSERT (pPresentationPosition);
+
+ // The call must be from event driven mode
+ if(m_ulNotificationsPerBuffer == 0)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ return GetPresentationPosition(pPresentationPosition);
+}
+
+//=============================================================================
+#pragma code_seg()
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS CMiniportWaveRTStream::GetPacketCount
+(
+ _Out_ ULONG *pPacketCount
+)
+{
+ ASSERT(pPacketCount);
+
+ // The call must be from event driven mode
+ if(m_ulNotificationsPerBuffer == 0)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ KIRQL oldIrql;
+ KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql);
+
+ if (m_KsState == KSSTATE_RUN)
+ {
+ // Get the current time and update simulated position.
+ LARGE_INTEGER ilQPC = KeQueryPerformanceCounter(NULL);
+ UpdatePosition(ilQPC);
+ }
+
+ *pPacketCount = LODWORD(m_llPacketCounter);
+ KeReleaseSpinLock(&m_PositionSpinLock, oldIrql);
+
+ return STATUS_SUCCESS;
+}
+
+//linear and presentation positions
+#pragma code_seg()
+NTSTATUS CMiniportWaveRTStream::GetPositions(
+ _Out_opt_ ULONGLONG* _pullLinearBufferPosition,
+ _Out_opt_ ULONGLONG* _pullPresentationPosition,
+ _Out_opt_ LARGE_INTEGER* _pliQPCTime
+)
+{
+ DPF_ENTER(("[CMiniportWaveRTStream::GetPositions]"));
+
+ NTSTATUS ntStatus;
+ LARGE_INTEGER ilQPC;
+ KIRQL oldIrql;
+
+ // Update *_pullLinearBufferPosition with the the number of bytes fetched from waveRT ever since a stream got set into RUN
+ // state.
+ // Once the stream is set to STOP state, any further read on this call would return zero.
+
+ //
+ // Get the current time and update position.
+ //
+ KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql);
+ ilQPC = KeQueryPerformanceCounter(NULL);
+ if (m_KsState == KSSTATE_RUN)
+ {
+ UpdatePosition(ilQPC);
+ }
+ if (_pullLinearBufferPosition)
+ {
+ *_pullLinearBufferPosition = m_ullLinearPosition;
+ }
+ if (_pullPresentationPosition)
+ {
+ *_pullPresentationPosition = m_ullPresentationPosition;
+ }
+ KeReleaseSpinLock(&m_PositionSpinLock, oldIrql);
+ if (_pliQPCTime)
+ {
+ *_pliQPCTime = ilQPC;
+ }
+
+ ntStatus = STATUS_SUCCESS;
+
+ return ntStatus;
+}
+
+NTSTATUS CMiniportWaveRTStream::GetPresentationPosition(_Out_ KSAUDIO_PRESENTATION_POSITION* _pPresentationPosition)
+{
+ ASSERT(_pPresentationPosition);
+ LARGE_INTEGER timeStamp;
+
+ DPF_ENTER(("[CMiniportWaveRTStream::GetPresentationPosition]"));
+
+ ULONGLONG ullLinearPosition = { 0 };
+ ULONGLONG ullPresentationPosition = { 0 };
+ NTSTATUS status = STATUS_SUCCESS;
+
+ status = GetPositions(&ullLinearPosition, &ullPresentationPosition, &timeStamp);
+ if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+
+ _pPresentationPosition->u64PositionInBlocks = ullPresentationPosition * m_pWfExt->Format.nSamplesPerSec / m_pWfExt->Format.nAvgBytesPerSec;
+ _pPresentationPosition->u64QPCPosition = (UINT64)timeStamp.QuadPart;
+
+ return STATUS_SUCCESS;
+}
+
+#pragma code_seg()
+NTSTATUS CMiniportWaveRTStream::SetCurrentWritePositionInternal(_In_ ULONG _ulCurrentWritePosition)
+{
+ DPF_ENTER(("[CMiniportWaveRTStream::SetCurrentWritePositionInternal]"));
+
+ ASSERT(m_bEoSReceived == FALSE);
+
+ if (m_bEoSReceived)
+ {
+ return STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ if (_ulCurrentWritePosition > m_ulDmaBufferSize)
+ {
+ return STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ PADAPTERCOMMON pAdapterComm = m_pMiniport->GetAdapterCommObj();
+
+ //Event type: eMINIPORT_SET_WAVERT_BUFFER_WRITE_POSITION
+ //Parameter 1: Current linear buffer position
+ //Parameter 2: Previous WaveRtBufferWritePosition that the driver received
+ //Parameter 3: Target WaveRtBufferWritePosition received from portcls
+ //Parameter 4: 0
+ pAdapterComm->WriteEtwEvent(eMINIPORT_SET_WAVERT_BUFFER_WRITE_POSITION,
+ m_ullLinearPosition, // replace with the correct "Current linear buffer position"
+ m_ulCurrentWritePosition,
+ _ulCurrentWritePosition, // this is new write position
+ 0); // always zero
+
+//
+// Check for eMINIPORT_GLITCH_REPORT - Same WaveRT buffer write during event driven mode.
+//
+ if (m_ulNotificationIntervalMs > 0)
+ {
+ if (m_ulCurrentWritePosition == _ulCurrentWritePosition)
+ {
+ //Event type: eMINIPORT_GLITCH_REPORT
+ //Parameter 1: Current linear buffer position
+ //Parameter 2: Previous WaveRtBufferWritePosition that the driver received
+ //Parameter 3: Major glitch code: 3: Received same WaveRT buffer twice in a row during event driven mode
+ //Parameter 4: Minor code for the glitch cause
+ pAdapterComm->WriteEtwEvent(eMINIPORT_GLITCH_REPORT,
+ m_ullLinearPosition, // replace with the correct "Current linear buffer position"
+ m_ulCurrentWritePosition,
+ 3, // received same WaveRT buffer twice in a row during event driven mode
+ _ulCurrentWritePosition);
+ }
+ }
+
+ m_ulCurrentWritePosition = _ulCurrentWritePosition;
+ InterlockedExchange(&m_IsCurrentWritePositionUpdated, 1);
+
+ return STATUS_SUCCESS;
+}
+
+//=============================================================================
+#pragma code_seg()
+NTSTATUS CMiniportWaveRTStream::SetState
+(
+ _In_ KSSTATE State_
+)
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ KIRQL oldIrql;
+
+ // Spew an event for a pin state change request from portcls
+ //Event type: eMINIPORT_PIN_STATE
+ switch (State_)
+ {
+ case KSSTATE_STOP:
+ if (m_KsState == KSSTATE_ACQUIRE)
+ {
+ // Acquire stream resources
+ }
+ KeAcquireSpinLock(&m_PositionSpinLock, &oldIrql);
+ // Reset DMA
+ m_llPacketCounter = 0;
+ m_ullPlayPosition = 0;
+ m_ullWritePosition = 0;
+ m_ullLinearPosition = 0;
+ m_ullPresentationPosition = 0;
+
+ // Reset OS read/write positions
+ m_ulLastOsReadPacket = ULONG_MAX;
+ m_ulCurrentWritePosition = 0;
+ m_ulLastOsWritePacket = ULONG_MAX;
+ m_bEoSReceived = FALSE;
+ m_bLastBufferRendered = FALSE;
+
+ KeReleaseSpinLock(&m_PositionSpinLock, oldIrql);
+
+ // Wait until all work items are completed.
+ if (!m_bCapture && !g_DoNotCreateDataFiles)
+ {
+ m_SaveData.WaitAllWorkItems();
+ }
+ break;
+
+ case KSSTATE_ACQUIRE:
+ if (m_KsState == KSSTATE_STOP)
+ {
+ // Acquire stream resources
+ }
+ break;
+
+ case KSSTATE_PAUSE:
+
+ if (m_KsState > KSSTATE_PAUSE)
+ {
+ //
+ // Run -> Pause
+ //
+
+ // Pause DMA
+ if (m_ulNotificationIntervalMs > 0)
+ {
+ ExCancelTimer(m_pNotificationTimer, NULL);
+ KeFlushQueuedDpcs();
+
+ // If pin is transitioning from RUN, save the time since last buffer completion event was sent
+ // so if the pin goes to RUN state again we can send the buffer completion event at correct time.
+ if (m_ullLastDPCTimeStamp > 0)
+ {
+ LARGE_INTEGER qpc;
+ LARGE_INTEGER qpcFrequency;
+ LONGLONG hnsCurrentTime;
+
+ qpc = KeQueryPerformanceCounter(&qpcFrequency);
+
+ // Convert ticks to 100ns units.
+ hnsCurrentTime = KSCONVERT_PERFORMANCE_TIME(m_ullPerformanceCounterFrequency.QuadPart, qpc);
+ m_hnsDPCTimeCarryForward = hnsCurrentTime - m_ullLastDPCTimeStamp + m_hnsDPCTimeCarryForward;
+ }
+ }
+ }
+ // This call updates the linear buffer and presentation positions.
+ GetPositions(NULL, NULL, NULL);
+ break;
+
+ case KSSTATE_RUN:
+ // Start DMA
+ LARGE_INTEGER ullPerfCounterTemp;
+ ullPerfCounterTemp = KeQueryPerformanceCounter(&m_ullPerformanceCounterFrequency);
+ m_ullLastDPCTimeStamp = m_ullDmaTimeStamp = KSCONVERT_PERFORMANCE_TIME(m_ullPerformanceCounterFrequency.QuadPart, ullPerfCounterTemp);
+
+ if (m_ulNotificationIntervalMs > 0)
+ {
+ // Set timer for 1 ms. This will cause DPC to run every 1 ms but driver will send out
+ // notification events only after notification interval. This timer is used by Simple Audio Sample to
+ // emulate hardware and send out notification event. Real hardware should not use this
+ // timer to fire notification event as it will drain power if the timer is running at 1 msec.
+ ExSetTimer
+ (
+ m_pNotificationTimer,
+ (-1) * HNSTIME_PER_MILLISECOND,
+ HNSTIME_PER_MILLISECOND, // 1 ms
+ NULL
+ );
+
+ }
+
+ break;
+ }
+
+ m_KsState = State_;
+
+ return ntStatus;
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS CMiniportWaveRTStream::SetFormat
+(
+ _In_ KSDATAFORMAT *DataFormat_
+)
+{
+ UNREFERENCED_PARAMETER(DataFormat_);
+
+ PAGED_CODE();
+
+ //if (!m_fCapture && !g_DoNotCreateDataFiles)
+ //{
+ // ntStatus = m_SaveData.SetDataFormat(Format);
+ //}
+
+ return STATUS_NOT_SUPPORTED;
+}
+
+#pragma code_seg()
+
+//=============================================================================
+#pragma code_seg()
+VOID CMiniportWaveRTStream::UpdatePosition
+(
+ _In_ LARGE_INTEGER ilQPC
+)
+{
+ // Convert ticks to 100ns units.
+ LONGLONG hnsCurrentTime = KSCONVERT_PERFORMANCE_TIME(m_ullPerformanceCounterFrequency.QuadPart, ilQPC);
+
+ // Calculate the time elapsed since the last call to GetPosition() or since the
+ // DMA engine started. Note that the division by 10000 to convert to milliseconds
+ // may cause us to lose some of the time, so we will carry the remainder forward
+ // to the next GetPosition() call.
+ //
+ ULONG TimeElapsedInMS = (ULONG)(hnsCurrentTime - m_ullDmaTimeStamp + m_hnsElapsedTimeCarryForward)/10000;
+
+ // Carry forward the remainder of this division so we don't fall behind with our position too much.
+ //
+ m_hnsElapsedTimeCarryForward = (hnsCurrentTime - m_ullDmaTimeStamp + m_hnsElapsedTimeCarryForward) % 10000;
+
+ // Calculate how many bytes in the DMA buffer would have been processed in the elapsed
+ // time. Note that the division by 1000 to convert to milliseconds may cause us to
+ // lose some bytes, so we will carry the remainder forward to the next GetPosition() call.
+ //
+ // need to divide by 1000 because m_ulDmaMovementRate is average bytes per sec.
+
+ ULONG ByteDisplacement = ((m_ulDmaMovementRate * TimeElapsedInMS) + m_byteDisplacementCarryForward) / 1000 ;
+ m_byteDisplacementCarryForward = ((m_ulDmaMovementRate * TimeElapsedInMS) + m_byteDisplacementCarryForward) % 1000;
+
+ // Increment presentation position even after last buffer is rendered.
+ m_ullPresentationPosition += ByteDisplacement;
+
+ if (m_bCapture)
+ {
+ // Write sine wave to buffer.
+ WriteBytes(ByteDisplacement);
+ }
+ else
+ {
+
+ if (m_bEoSReceived)
+ {
+ // since EoS flag is set, we'll need to make sure not to read data beyond EOS position.
+ // If driver's current position is less than EoS position, then make sure not to read data beyond EoS.
+ if (m_ullWritePosition <= m_ulCurrentWritePosition)
+ {
+ ByteDisplacement = min(ByteDisplacement, m_ulCurrentWritePosition - (ULONG)m_ullWritePosition);
+ }
+ // If our current position is ahead of EoS position and we'll wrap around after new position then adjust
+ // new position if it crosses EoS.
+ else if ((m_ullWritePosition + ByteDisplacement) % m_ulDmaBufferSize < m_ullWritePosition)
+ {
+ if ((m_ullWritePosition + ByteDisplacement) % m_ulDmaBufferSize > m_ulCurrentWritePosition)
+ {
+ ByteDisplacement = ByteDisplacement - (((ULONG)m_ullWritePosition + ByteDisplacement) % m_ulDmaBufferSize - m_ulCurrentWritePosition);
+ }
+ }
+ }
+
+ // If the last packet was rendered(read in the sample driver's case), send out an etw event.
+ if (m_bEoSReceived && !m_bLastBufferRendered
+ && (m_ullWritePosition + ByteDisplacement) % m_ulDmaBufferSize == m_ulCurrentWritePosition)
+ {
+ m_bLastBufferRendered = TRUE;
+ }
+
+ if (!g_DoNotCreateDataFiles)
+ {
+ // Read from buffer and write to a file.
+ ReadBytes(ByteDisplacement);
+ }
+ }
+
+ // Increment the DMA position by the number of bytes displaced since the last
+ // call to UpdatePosition() and ensure we properly wrap at buffer length.
+ //
+ m_ullPlayPosition = m_ullWritePosition =
+ (m_ullWritePosition + ByteDisplacement) % m_ulDmaBufferSize;
+
+ // m_ullDmaTimeStamp is updated in both GetPostion and GetLinearPosition calls
+ // so m_ullLinearPosition needs to be updated accordingly here
+ //
+ m_ullLinearPosition += ByteDisplacement;
+
+ // Update the DMA time stamp for the next call to GetPosition()
+ //
+ m_ullDmaTimeStamp = hnsCurrentTime;
+}
+
+//=============================================================================
+#pragma code_seg()
+VOID CMiniportWaveRTStream::WriteBytes
+(
+ _In_ ULONG ByteDisplacement
+)
+/*++
+
+Routine Description:
+
+This function writes the audio buffer using a sine wave generator
+
+Arguments:
+
+ByteDisplacement - # of bytes to process.
+
+--*/
+{
+ ULONG bufferOffset = m_ullLinearPosition % m_ulDmaBufferSize;
+
+ // Normally this will loop no more than once for a single wrap, but if
+ // many bytes have been displaced then this may loops many times.
+ while (ByteDisplacement > 0)
+ {
+ ULONG runWrite = min(ByteDisplacement, m_ulDmaBufferSize - bufferOffset);
+
+ m_ToneGenerator.GenerateSine(m_pDmaBuffer + bufferOffset, runWrite);
+
+ bufferOffset = (bufferOffset + runWrite) % m_ulDmaBufferSize;
+ ByteDisplacement -= runWrite;
+ }
+}
+
+//=============================================================================
+#pragma code_seg()
+VOID CMiniportWaveRTStream::ReadBytes
+(
+ _In_ ULONG ByteDisplacement
+)
+/*++
+
+Routine Description:
+
+This function reads the audio buffer and saves the data in a file.
+
+Arguments:
+
+ByteDisplacement - # of bytes to process.
+
+--*/
+{
+ ULONG bufferOffset = m_ullLinearPosition % m_ulDmaBufferSize;
+
+ // Normally this will loop no more than once for a single wrap, but if
+ // many bytes have been displaced then this may loops many times.
+ while (ByteDisplacement > 0)
+ {
+ ULONG runWrite = min(ByteDisplacement, m_ulDmaBufferSize - bufferOffset);
+ m_SaveData.WriteData(m_pDmaBuffer + bufferOffset, runWrite);
+ bufferOffset = (bufferOffset + runWrite) % m_ulDmaBufferSize;
+ ByteDisplacement -= runWrite;
+ }
+}
+
+//=============================================================================
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CMiniportWaveRTStream::SetContentId
+(
+ _In_ ULONG contentId,
+ _In_ PCDRMRIGHTS drmRights
+)
+/*++
+
+Routine Description:
+
+ Sets DRM content Id for this stream. Also updates the Mixed content Id.
+
+Arguments:
+
+ contentId - new content id
+
+ drmRights - rights for this stream.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CMiniportWaveRT::SetContentId]"));
+
+ NTSTATUS ntStatus;
+ ULONG ulOldContentId = contentId;
+
+ m_ulContentId = contentId;
+
+ //
+ // Miniport should create a mixed DrmRights.
+ //
+ ntStatus = m_pMiniport->UpdateDrmRights();
+
+ //
+ // Restore the passed-in content Id.
+ //
+ if (!NT_SUCCESS(ntStatus))
+ {
+ m_ulContentId = ulOldContentId;
+ }
+
+ //
+ // Simple Audio Sample writes each stream seperately to disk. If the rights for this
+ // stream indicates that the stream is CopyProtected, stop writing to disk.
+ //
+ m_SaveData.Disable(drmRights->CopyProtect);
+
+ //
+ // From MSDN:
+ //
+ // This sample doesn't forward protected content, but if your driver uses
+ // lower layer drivers or a different stack to properly work, please see the
+ // following info from MSDN:
+ //
+ // "Before allowing protected content to flow through a data path, the system
+ // verifies that the data path is secure. To do so, the system authenticates
+ // each module in the data path beginning at the upstream end of the data path
+ // and moving downstream. As each module is authenticated, that module gives
+ // the system information about the next module in the data path so that it
+ // can also be authenticated. To be successfully authenticated, a module's
+ // binary file must be signed as DRM-compliant.
+ //
+ // Two adjacent modules in the data path can communicate with each other in
+ // one of several ways. If the upstream module calls the downstream module
+ // through IoCallDriver, the downstream module is part of a WDM driver. In
+ // this case, the upstream module calls the DrmForwardContentToDeviceObject
+ // function to provide the system with the device object representing the
+ // downstream module. (If the two modules communicate through the downstream
+ // module's COM interface or content handlers, the upstream module calls
+ // DrmForwardContentToInterface or DrmAddContentHandlers instead.)
+ //
+ // DrmForwardContentToDeviceObject performs the same function as
+ // PcForwardContentToDeviceObject and IDrmPort2::ForwardContentToDeviceObject."
+ //
+ // Other supported DRM DDIs for down-level module validation are:
+ // DrmForwardContentToInterfaces and DrmAddContentHandlers.
+ //
+ // For more information, see MSDN's DRM Functions and Interfaces.
+ //
+
+ return ntStatus;
+} // SetContentId
+
+//=============================================================================
+#pragma code_seg()
+void
+TimerNotifyRT
+(
+ _In_ PEX_TIMER Timer,
+ _In_opt_ PVOID DeferredContext
+)
+{
+ LARGE_INTEGER qpc;
+ LARGE_INTEGER qpcFrequency;
+ BOOL bufferCompleted = FALSE;
+
+ UNREFERENCED_PARAMETER(Timer);
+
+ _IRQL_limited_to_(DISPATCH_LEVEL);
+
+ CMiniportWaveRTStream* _this = (CMiniportWaveRTStream*)DeferredContext;
+
+ if (NULL == _this)
+ {
+ return;
+ }
+
+ KIRQL oldIrql;
+ KeAcquireSpinLock(&_this->m_PositionSpinLock, &oldIrql);
+
+ qpc = KeQueryPerformanceCounter(&qpcFrequency);
+
+ // Convert ticks to 100ns units.
+ LONGLONG hnsCurrentTime = KSCONVERT_PERFORMANCE_TIME(_this->m_ullPerformanceCounterFrequency.QuadPart, qpc);
+
+ // Calculate the time elapsed since the last we ran DPC that matched Notification interval. Note that the division by 10000
+ // to convert to milliseconds may cause us to lose some of the time, so we will carry the remainder forward.
+
+ ULONG TimeElapsedInMS = (ULONG)(hnsCurrentTime - _this->m_ullLastDPCTimeStamp + _this->m_hnsDPCTimeCarryForward)/10000;
+
+ if (TimeElapsedInMS >= _this->m_ulNotificationIntervalMs)
+ {
+ // Carry forward the time greater than notification interval to adjust time to signal next buffer completion event accordingly.
+ _this->m_hnsDPCTimeCarryForward = hnsCurrentTime - _this->m_ullLastDPCTimeStamp + _this->m_hnsDPCTimeCarryForward - (_this->m_ulNotificationIntervalMs * 10000);
+ // Save the last time DPC ran at notification interval
+ _this->m_ullLastDPCTimeStamp = hnsCurrentTime;
+ bufferCompleted = TRUE;
+ }
+
+ if (!bufferCompleted && !_this->m_bEoSReceived)
+ {
+ goto End;
+ }
+
+ _this->UpdatePosition(qpc);
+
+ if (!_this->m_bEoSReceived)
+ {
+ _this->m_llPacketCounter++;
+ }
+
+ if (_this->m_KsState != KSSTATE_RUN)
+ {
+ goto End;
+ }
+
+ PADAPTERCOMMON pAdapterComm = _this->m_pMiniport->GetAdapterCommObj();
+
+ // Simple buffer underrun detection.
+ if (!_this->IsCurrentWaveRTWritePositionUpdated() && !_this->m_bEoSReceived)
+ {
+ //Event type: eMINIPORT_GLITCH_REPORT
+ //Parameter 1: Current linear buffer position
+ //Parameter 2: Previous WaveRtBufferWritePosition that the driver received
+ //Parameter 3: Major glitch code: 1:WaveRT buffer is underrun
+ //Parameter 4: Minor code for the glitch cause
+ pAdapterComm->WriteEtwEvent(eMINIPORT_GLITCH_REPORT,
+ _this->m_ullLinearPosition,
+ _this->GetCurrentWaveRTWritePosition(),
+ 1, // WaveRT buffer is underrun
+ 0);
+ }
+
+ // Send buffer completion event if either of the following is true
+ // 1. Driver consumed a complete buffer for this stream
+ // 2. Driver consumed a partial buffer containing EoS for this stream
+
+ if (!IsListEmpty(&_this->m_NotificationList) &&
+ (bufferCompleted || _this->m_bLastBufferRendered))
+ {
+ PLIST_ENTRY leCurrent = _this->m_NotificationList.Flink;
+ while (leCurrent != &_this->m_NotificationList)
+ {
+ NotificationListEntry* nleCurrent = CONTAINING_RECORD( leCurrent, NotificationListEntry, ListEntry);
+ KeSetEvent(nleCurrent->NotificationEvent, 0, 0);
+
+ leCurrent = leCurrent->Flink;
+ }
+ }
+
+ if (_this->m_bLastBufferRendered)
+ {
+ ExCancelTimer(_this->m_pNotificationTimer, NULL);
+ }
+
+End:
+ KeReleaseSpinLock(&_this->m_PositionSpinLock, oldIrql);
+ return;
+}
+//=============================================================================
+
diff --git a/audio/simpleaudiosample/Source/Main/minwavertstream.h b/audio/simpleaudiosample/Source/Main/minwavertstream.h
new file mode 100644
index 00000000..5545e0d8
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Main/minwavertstream.h
@@ -0,0 +1,248 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ minwavertstream.h
+
+Abstract:
+
+ Definition of wavert miniport class.
+--*/
+
+#ifndef _SIMPLEAUDIOSAMPLE_MINWAVERTSTREAM_H_
+#define _SIMPLEAUDIOSAMPLE_MINWAVERTSTREAM_H_
+
+#include "savedata.h"
+#include "ToneGenerator.h"
+
+//
+// Structure to store notifications events in a protected list
+//
+typedef struct _NotificationListEntry
+{
+ LIST_ENTRY ListEntry;
+ PKEVENT NotificationEvent;
+} NotificationListEntry;
+
+EXT_CALLBACK TimerNotifyRT;
+
+//=============================================================================
+// Referenced Forward
+//=============================================================================
+class CMiniportWaveRT;
+typedef CMiniportWaveRT *PCMiniportWaveRT;
+
+//=============================================================================
+// Classes
+//=============================================================================
+///////////////////////////////////////////////////////////////////////////////
+// CMiniportWaveRTStream
+//
+class CMiniportWaveRTStream :
+ public IDrmAudioStream,
+ public IMiniportWaveRTStreamNotification,
+ public IMiniportWaveRTInputStream,
+ public IMiniportWaveRTOutputStream,
+ public CUnknown
+{
+protected:
+ PPORTWAVERTSTREAM m_pPortStream;
+ LIST_ENTRY m_NotificationList;
+ PEX_TIMER m_pNotificationTimer;
+ ULONG m_ulNotificationIntervalMs;
+ ULONG m_ulCurrentWritePosition;
+ LONG m_IsCurrentWritePositionUpdated;
+
+public:
+ DECLARE_STD_UNKNOWN();
+ DEFINE_STD_CONSTRUCTOR(CMiniportWaveRTStream);
+ ~CMiniportWaveRTStream();
+
+ IMP_IMiniportWaveRTStream;
+ IMP_IMiniportWaveRTStreamNotification;
+ IMP_IMiniportWaveRTInputStream;
+ IMP_IMiniportWaveRTOutputStream;
+ IMP_IMiniportWaveRT;
+ IMP_IDrmAudioStream;
+
+ NTSTATUS Init
+ (
+ _In_ PCMiniportWaveRT Miniport,
+ _In_ PPORTWAVERTSTREAM Stream,
+ _In_ ULONG Channel,
+ _In_ BOOLEAN Capture,
+ _In_ PKSDATAFORMAT DataFormat,
+ _In_ GUID SignalProcessingMode
+ );
+
+ // Friends
+ friend class CMiniportWaveRT;
+ friend EXT_CALLBACK TimerNotifyRT;
+protected:
+ CMiniportWaveRT* m_pMiniport;
+ ULONG m_ulPin;
+ BOOLEAN m_bCapture;
+ BOOLEAN m_bUnregisterStream;
+ ULONG m_ulDmaBufferSize;
+ BYTE* m_pDmaBuffer;
+ ULONG m_ulNotificationsPerBuffer;
+ KSSTATE m_KsState;
+ PKTIMER m_pTimer;
+ PRKDPC m_pDpc;
+ ULONGLONG m_ullPlayPosition;
+ ULONGLONG m_ullWritePosition;
+ ULONGLONG m_ullLinearPosition;
+ ULONGLONG m_ullPresentationPosition;
+ ULONG m_ulLastOsReadPacket;
+ ULONG m_ulLastOsWritePacket;
+ LONGLONG m_llPacketCounter;
+ ULONGLONG m_ullDmaTimeStamp;
+ LARGE_INTEGER m_ullPerformanceCounterFrequency;
+ ULONGLONG m_hnsElapsedTimeCarryForward;
+ ULONGLONG m_ullLastDPCTimeStamp;
+ ULONGLONG m_hnsDPCTimeCarryForward;
+ ULONG m_byteDisplacementCarryForward;
+ ULONG m_ulDmaMovementRate;
+ BOOL m_bLfxEnabled;
+ PBOOL m_pbMuted;
+ PLONG m_plVolumeLevel;
+ PLONG m_plPeakMeter;
+ PWAVEFORMATEXTENSIBLE m_pWfExt;
+ ULONG m_ulContentId;
+ CSaveData m_SaveData;
+ ToneGenerator m_ToneGenerator;
+ GUID m_SignalProcessingMode;
+ BOOLEAN m_bEoSReceived;
+ BOOLEAN m_bLastBufferRendered;
+ KSPIN_LOCK m_PositionSpinLock;
+ // Member variable as config params for tone generator
+ ULONG m_ulHostCaptureToneFrequency;
+ // If abs(m_dwHostCaptureToneAmplitude) + abs(m_dwHostCaptureToneDCValue) > 100
+ // m_dwHostCaptureToneDCValue will be compensated to make the sum equal to 100
+ DWORD m_dwHostCaptureToneAmplitude; // must be between -100 to 100
+ DWORD m_dwLoopbackCaptureToneAmplitude; // must be between -100 to 100
+ DWORD m_dwHostCaptureToneDCOffset; // must be between -100 to 100
+ DWORD m_dwLoopbackCaptureToneDCOffset; // must be between -100 to 100
+ DWORD m_dwHostCaptureToneInitialPhase; // must be between -31416 to 31416
+ DWORD m_dwLoopbackCaptureToneInitialPhase; // must be between -31416 to 31416
+ // Member variable as config params for tone generator
+
+public:
+
+ NTSTATUS GetVolumeChannelCount
+ (
+ _Out_ UINT32* puiChannelCount
+ );
+
+ NTSTATUS GetVolumeSteppings
+ (
+ _Out_writes_bytes_(_ui32DataSize) PKSPROPERTY_STEPPING_LONG _pKsPropStepLong,
+ _In_ UINT32 _ui32DataSize
+ );
+
+ NTSTATUS GetChannelVolume
+ (
+ _In_ UINT32 _uiChannel,
+ _Out_ LONG* _pVolume
+ );
+
+ NTSTATUS SetChannelVolume
+ (
+ _In_ UINT32 _uiChannel,
+ _In_ LONG _Volume
+ );
+
+ NTSTATUS GetMuteChannelCount
+ (
+ _Out_ UINT32* puiChannelCount
+ );
+
+ NTSTATUS GetMuteSteppings
+ (
+ _Out_writes_bytes_(_ui32DataSize) PKSPROPERTY_STEPPING_LONG _pKsPropStepLong,
+ _In_ UINT32 _ui32DataSize
+ );
+
+ NTSTATUS GetChannelMute
+ (
+ _In_ UINT32 _uiChannel,
+ _Out_ BOOL* _pbMute
+ );
+
+ NTSTATUS SetChannelMute
+ (
+ _In_ UINT32 _uiChannel,
+ _In_ BOOL _bMute
+ );
+
+ //presentation
+ NTSTATUS GetPresentationPosition
+ (
+ _Out_ KSAUDIO_PRESENTATION_POSITION *_pPresentationPosition
+ );
+
+ NTSTATUS SetCurrentWritePosition
+ (
+ _In_ ULONG ulCurrentWritePosition
+ );
+
+
+ ULONG GetCurrentWaveRTWritePosition()
+ {
+ return m_ulCurrentWritePosition;
+ };
+
+ // To support simple underrun validation.
+ BOOL IsCurrentWaveRTWritePositionUpdated()
+ {
+ return InterlockedExchange(&m_IsCurrentWritePositionUpdated, 0) ? TRUE : FALSE;
+ };
+
+ GUID GetSignalProcessingMode()
+ {
+ return m_SignalProcessingMode;
+ }
+
+private:
+
+ //
+ // Helper functions.
+ //
+
+#pragma code_seg()
+
+ VOID WriteBytes
+ (
+ _In_ ULONG ByteDisplacement
+ );
+
+ VOID ReadBytes
+ (
+ _In_ ULONG ByteDisplacement
+ );
+
+ VOID UpdatePosition
+ (
+ _In_ LARGE_INTEGER ilQPC
+ );
+
+ NTSTATUS SetCurrentWritePositionInternal
+ (
+ _In_ ULONG ulCurrentWritePosition
+ );
+
+ NTSTATUS GetPositions
+ (
+ _Out_opt_ ULONGLONG * _pullLinearBufferPosition,
+ _Out_opt_ ULONGLONG * _pullPresentationPosition,
+ _Out_opt_ LARGE_INTEGER * _pliQPCTime
+ );
+
+ NTSTATUS ReadRegistrySettings();
+
+};
+typedef CMiniportWaveRTStream *PCMiniportWaveRTStream;
+#endif // _SIMPLEAUDIOSAMPLE_MINWAVERTSTREAM_H_
+
diff --git a/audio/simpleaudiosample/Source/Utilities/ToneGenerator.cpp b/audio/simpleaudiosample/Source/Utilities/ToneGenerator.cpp
new file mode 100644
index 00000000..f50e81e1
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Utilities/ToneGenerator.cpp
@@ -0,0 +1,285 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ ToneGenerator
+
+Abstract:
+
+ Implementation of Simple Audio Sample sine wave generator
+
+--*/
+#include "definitions.h"
+#include "ToneGenerator.h"
+
+const double TWO_PI = M_PI * 2;
+
+extern DWORD g_DisableToneGenerator;
+
+//
+// Double to long conversion.
+//
+long ConvertToLong(double Value)
+{
+ return (long)(Value * _I32_MAX);
+};
+
+//
+// Double to short conversion.
+//
+short ConvertToShort(double Value)
+{
+ return (short)(Value * _I16_MAX);
+};
+
+//
+// Double to char conversion.
+//
+unsigned char ConvertToUChar(double Value)
+{
+ const double F_127_5 = 127.5;
+ return (unsigned char)(Value * F_127_5 + F_127_5);
+};
+
+//
+// Ctor: basic init.
+//
+ToneGenerator::ToneGenerator()
+: m_Frequency(0),
+ m_ChannelCount(0),
+ m_BitsPerSample(0),
+ m_SamplesPerSecond(0),
+ m_Mute(false),
+ m_PartialFrame(NULL),
+ m_PartialFrameBytes(0),
+ m_FrameSize(0)
+{
+ // Theta (double) and SampleIncrement (double) are init in the Init() method
+ // after saving the floating point state.
+}
+
+//
+// Dtor: free resources.
+//
+ToneGenerator::~ToneGenerator()
+{
+ if (m_PartialFrame)
+ {
+ ExFreePoolWithTag(m_PartialFrame, SIMPLEAUDIOSAMPLE_POOLTAG);
+ m_PartialFrame = NULL;
+ m_PartialFrameBytes = 0;
+ }
+}
+
+//
+// Init a new frame.
+// Note: caller will save and restore the floatingpoint state.
+//
+#pragma warning(push)
+// Caller wraps this routine between KeSaveFloatingPointState/KeRestoreFloatingPointState calls.
+#pragma warning(disable: 28110)
+
+VOID ToneGenerator::InitNewFrame
+(
+ _Out_writes_bytes_(FrameSize) BYTE* Frame,
+ _In_ DWORD FrameSize
+)
+{
+ double sinValue = m_ToneDCOffset + m_ToneAmplitude * sin( m_Theta );
+
+ if (FrameSize != (DWORD)m_ChannelCount * m_BitsPerSample/8)
+ {
+ ASSERT(FALSE);
+ RtlZeroMemory(Frame, FrameSize);
+ return;
+ }
+
+ for(ULONG i = 0; i < m_ChannelCount; ++i)
+ {
+ if (m_BitsPerSample == 8)
+ {
+ unsigned char *dataBuffer = reinterpret_cast<unsigned char *>(Frame);
+ dataBuffer[i] = ConvertToUChar(sinValue);
+ }
+ else if (m_BitsPerSample == 16)
+ {
+ short *dataBuffer = reinterpret_cast<short *>(Frame);
+ dataBuffer[i] = ConvertToShort(sinValue);
+ }
+ else if (m_BitsPerSample == 24)
+ {
+ BYTE *dataBuffer = Frame;
+ long val = ConvertToLong(sinValue);
+ val = val >> 8;
+ RtlCopyMemory(dataBuffer, &val, 3);
+ }
+ else if (m_BitsPerSample == 32)
+ {
+ long *dataBuffer = reinterpret_cast<long *>(Frame);
+ dataBuffer[i] = ConvertToLong(sinValue);
+ }
+ }
+
+ m_Theta += m_SampleIncrement;
+ if (m_Theta >= TWO_PI)
+ {
+ m_Theta -= TWO_PI;
+ }
+}
+#pragma warning(pop)
+
+//
+// GenerateSamples()
+//
+// Generate a sine wave that fits into the specified buffer.
+//
+// Buffer - Buffer to hold the samples
+// BufferLength - Length of the buffer.
+//
+//
+void ToneGenerator::GenerateSine
+(
+ _Out_writes_bytes_(BufferLength) BYTE *Buffer,
+ _In_ size_t BufferLength
+)
+{
+ NTSTATUS status;
+ KFLOATING_SAVE saveData;
+ BYTE * buffer;
+ size_t length;
+ size_t copyBytes;
+
+ // if muted, or tone generator disabled via registry,
+ // we deliver silence.
+ if (m_Mute || g_DisableToneGenerator)
+ {
+ goto ZeroBuffer;
+ }
+
+ status = KeSaveFloatingPointState(&saveData);
+ if (!NT_SUCCESS(status))
+ {
+ goto ZeroBuffer;
+ }
+
+ buffer = Buffer;
+ length = BufferLength;
+
+ //
+ // Check if we have any residual frame bytes from the last time.
+ //
+ if (m_PartialFrameBytes)
+ {
+ ASSERT(m_FrameSize > m_PartialFrameBytes);
+ DWORD offset = m_FrameSize - m_PartialFrameBytes;
+ copyBytes = MIN(m_PartialFrameBytes, length);
+ RtlCopyMemory(buffer, m_PartialFrame + offset, copyBytes);
+ RtlZeroMemory(m_PartialFrame + offset, copyBytes);
+ length -= copyBytes;
+ buffer += copyBytes;
+ m_PartialFrameBytes = 0;
+ }
+
+ IF_TRUE_JUMP(length == 0, Done);
+
+ //
+ // Copy all the aligned frames.
+ //
+
+ size_t frames = length/m_FrameSize;
+
+ for (size_t i = 0; i < frames; ++i)
+ {
+ InitNewFrame(buffer, m_FrameSize);
+ buffer += m_FrameSize;
+ length -= m_FrameSize;
+ }
+
+ IF_TRUE_JUMP(length == 0, Done);
+
+ //
+ // Copy any partial frame at the end.
+ //
+ ASSERT(m_FrameSize > length);
+ InitNewFrame(m_PartialFrame, m_FrameSize);
+ RtlCopyMemory(buffer, m_PartialFrame, length);
+ RtlZeroMemory(m_PartialFrame, length);
+ m_PartialFrameBytes = m_FrameSize - (DWORD)length;
+
+Done:
+ KeRestoreFloatingPointState(&saveData);
+ return;
+
+ZeroBuffer:
+ RtlZeroMemory(Buffer, BufferLength);
+ return;
+}
+
+NTSTATUS ToneGenerator::Init
+(
+ _In_ DWORD ToneFrequency,
+ _In_ double ToneAmplitude,
+ _In_ double ToneDCOffset,
+ _In_ double ToneInitialPhase,
+ _In_ PWAVEFORMATEXTENSIBLE WfExt
+)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ KFLOATING_SAVE saveData;
+
+ //
+ // This sample supports PCM formats only.
+ //
+ if ((WfExt->Format.wFormatTag != WAVE_FORMAT_PCM &&
+ !(WfExt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+ IsEqualGUIDAligned(WfExt->SubFormat, KSDATAFORMAT_SUBTYPE_PCM))))
+ {
+ status = STATUS_NOT_SUPPORTED;
+ }
+ IF_FAILED_JUMP(status, Done);
+
+ //
+ // Save floating state (just in case).
+ //
+ status = KeSaveFloatingPointState(&saveData);
+ IF_FAILED_JUMP(status, Done);
+
+ //
+ // Basic init.
+ //
+ m_Theta = ToneInitialPhase;
+ m_Frequency = ToneFrequency;
+ m_ToneAmplitude = ToneAmplitude;
+ m_ToneDCOffset = ToneDCOffset;
+
+ m_ChannelCount = WfExt->Format.nChannels; // # channels.
+ m_BitsPerSample = WfExt->Format.wBitsPerSample; // bits per sample.
+ m_SamplesPerSecond = WfExt->Format.nSamplesPerSec; // samples per sec.
+ m_Mute = false;
+ m_SampleIncrement = (m_Frequency * TWO_PI) / (double)m_SamplesPerSecond;
+ m_FrameSize = (DWORD)m_ChannelCount * m_BitsPerSample/8;
+ ASSERT(m_FrameSize == WfExt->Format.nBlockAlign);
+
+ //
+ // Restore floating state.
+ //
+ KeRestoreFloatingPointState(&saveData);
+
+ //
+ // Allocate a buffer to hold a partial frame.
+ //
+ m_PartialFrame = (BYTE*)ExAllocatePool2(
+ POOL_FLAG_NON_PAGED,
+ m_FrameSize,
+ SIMPLEAUDIOSAMPLE_POOLTAG);
+
+ IF_TRUE_ACTION_JUMP(m_PartialFrame == NULL, status = STATUS_INSUFFICIENT_RESOURCES, Done);
+
+ status = STATUS_SUCCESS;
+
+Done:
+ return status;
+}
+
diff --git a/audio/simpleaudiosample/Source/Utilities/ToneGenerator.h b/audio/simpleaudiosample/Source/Utilities/ToneGenerator.h
new file mode 100644
index 00000000..85b1229a
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Utilities/ToneGenerator.h
@@ -0,0 +1,74 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ ToneGenerator.h
+
+Abstract:
+
+ Declaration of Simple Audio Sample sine wave generator.
+--*/
+#ifndef _SIMPLEAUDIOSAMPLE_TONEGENERATOR_H
+#define _SIMPLEAUDIOSAMPLE_TONEGENERATOR_H
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+#include <limits.h>
+
+class ToneGenerator
+{
+public:
+ DWORD m_Frequency;
+ WORD m_ChannelCount;
+ WORD m_BitsPerSample;
+ DWORD m_SamplesPerSecond;
+ double m_Theta;
+ double m_SampleIncrement;
+ bool m_Mute;
+ BYTE* m_PartialFrame;
+ DWORD m_PartialFrameBytes;
+ DWORD m_FrameSize;
+ double m_ToneAmplitude;
+ double m_ToneDCOffset;
+
+public:
+ ToneGenerator();
+ ~ToneGenerator();
+
+ NTSTATUS
+ Init
+ (
+ _In_ DWORD ToneFrequency,
+ _In_ double ToneAmplitude,
+ _In_ double ToneDCOffset,
+ _In_ double ToneInitialPhase,
+ _In_ PWAVEFORMATEXTENSIBLE WfExt
+ );
+
+ VOID
+ GenerateSine
+ (
+ _Out_writes_bytes_(BufferLength) BYTE *Buffer,
+ _In_ size_t BufferLength
+ );
+
+ VOID
+ SetMute
+ (
+ _In_ bool Value
+ )
+ {
+ m_Mute = Value;
+ }
+
+private:
+ VOID InitNewFrame
+ (
+ _Out_writes_bytes_(FrameSize) BYTE* Frame,
+ _In_ DWORD FrameSize
+ );
+};
+
+#endif // _SIMPLEAUDIOSAMPLE_TONEGENERATOR_H
diff --git a/audio/simpleaudiosample/Source/Utilities/Utilities.vcxproj b/audio/simpleaudiosample/Source/Utilities/Utilities.vcxproj
new file mode 100644
index 00000000..0a71bf42
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Utilities/Utilities.vcxproj
@@ -0,0 +1,284 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|ARM64">
+ <Configuration>Debug</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|ARM64">
+ <Configuration>Release</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{33E61864-6F2C-4F9F-BE70-8F8985A4F283}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{F51739CE-5253-42B5-9191-57F28B5842C6}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>Utilities</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <TargetName>Utilities</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>Utilities</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <TargetName>Utilities</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>Utilities</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>Utilities</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..;.</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc;.</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;_NEW_DELETE_OPERATORS_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ <DisableSpecificWarnings>4595;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_</PreprocessorDefinitions>
+ </Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="hw.cpp" />
+ <ClCompile Include="kshelper.cpp" />
+ <ClCompile Include="savedata.cpp" />
+ <ClCompile Include="tonegenerator.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>
diff --git a/audio/sysvad/PhoneAudioSample/PhoneAudioSample.vcxproj.Filters b/audio/simpleaudiosample/Source/Utilities/Utilities.vcxproj.Filters
index c57611a0..7a4ebde2 100644
--- a/audio/sysvad/PhoneAudioSample/PhoneAudioSample.vcxproj.Filters
+++ b/audio/simpleaudiosample/Source/Utilities/Utilities.vcxproj.Filters
@@ -1,44 +1,31 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
- <UniqueIdentifier>{6BC89CB0-7C76-439F-8D55-E3125E355A42}</UniqueIdentifier>
+ <UniqueIdentifier>{CDBBEDA3-98E9-4C7A-BDB1-25EC47D0B087}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
- <UniqueIdentifier>{02E55FC1-89F6-4E2D-A10B-A6476FF89B86}</UniqueIdentifier>
+ <UniqueIdentifier>{FA3DF57E-BA19-4783-831B-CF9D4D594F70}</UniqueIdentifier>
</Filter>
<Filter Include="Resource Files">
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
- <UniqueIdentifier>{B836489B-8D2E-41DD-A232-0D6C40243B08}</UniqueIdentifier>
+ <UniqueIdentifier>{CB830E4F-01DA-4D35-9789-E7DB0D02A79C}</UniqueIdentifier>
</Filter>
<Filter Include="Driver Files">
<Extensions>inf;inv;inx;mof;mc;</Extensions>
- <UniqueIdentifier>{850E3B99-7C84-454B-9E04-6A7CF9852E6C}</UniqueIdentifier>
+ <UniqueIdentifier>{49F92783-3B39-4D0C-A153-8C346F754749}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
- <ClCompile Include="..\*.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
<ClCompile Include="*.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
- <ResourceCompile Include="PhoneAudioSample.rc">
- <Filter>Resource Files</Filter>
- </ResourceCompile>
- </ItemGroup>
- <ItemGroup>
<ClInclude Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
- <ItemGroup>
- <Inf Include="*.inx">
- <Filter>Driver Files</Filter>
- </Inf>
- </ItemGroup>
</Project>
diff --git a/audio/simpleaudiosample/Source/Utilities/hw.cpp b/audio/simpleaudiosample/Source/Utilities/hw.cpp
new file mode 100644
index 00000000..133bcc99
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Utilities/hw.cpp
@@ -0,0 +1,446 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ hw.cpp
+
+Abstract:
+
+ Implementation of Simple Audio Sample HW class.
+ Simple Audio Sample HW has an array for storing mixer and volume settings
+ for the topology.
+--*/
+#include "definitions.h"
+#include "hw.h"
+
+//=============================================================================
+// CSimpleAudioSampleHW
+//=============================================================================
+
+//=============================================================================
+#pragma code_seg("PAGE")
+CSimpleAudioSampleHW::CSimpleAudioSampleHW()
+: m_ulMux(0),
+ m_bDevSpecific(FALSE),
+ m_iDevSpecific(0),
+ m_uiDevSpecific(0)
+/*++
+
+Routine Description:
+
+ Constructor for SimpleAudioSampleHW.
+
+Arguments:
+
+Return Value:
+
+ void
+
+--*/
+{
+ PAGED_CODE();
+
+ MixerReset();
+} // SimpleAudioSampleHW
+#pragma code_seg()
+
+
+//=============================================================================
+BOOL
+CSimpleAudioSampleHW::bGetDevSpecific()
+/*++
+
+Routine Description:
+
+ Gets the HW (!) Device Specific info
+
+Arguments:
+
+ N/A
+
+Return Value:
+
+ True or False (in this example).
+
+--*/
+{
+ return m_bDevSpecific;
+} // bGetDevSpecific
+
+//=============================================================================
+void
+CSimpleAudioSampleHW::bSetDevSpecific
+(
+ _In_ BOOL bDevSpecific
+)
+/*++
+
+Routine Description:
+
+ Sets the HW (!) Device Specific info
+
+Arguments:
+
+ fDevSpecific - true or false for this example.
+
+Return Value:
+
+ void
+
+--*/
+{
+ m_bDevSpecific = bDevSpecific;
+} // bSetDevSpecific
+
+//=============================================================================
+INT
+CSimpleAudioSampleHW::iGetDevSpecific()
+/*++
+
+Routine Description:
+
+ Gets the HW (!) Device Specific info
+
+Arguments:
+
+ N/A
+
+Return Value:
+
+ int (in this example).
+
+--*/
+{
+ return m_iDevSpecific;
+} // iGetDevSpecific
+
+//=============================================================================
+void
+CSimpleAudioSampleHW::iSetDevSpecific
+(
+ _In_ INT iDevSpecific
+)
+/*++
+
+Routine Description:
+
+ Sets the HW (!) Device Specific info
+
+Arguments:
+
+ fDevSpecific - true or false for this example.
+
+Return Value:
+
+ void
+
+--*/
+{
+ m_iDevSpecific = iDevSpecific;
+} // iSetDevSpecific
+
+//=============================================================================
+UINT
+CSimpleAudioSampleHW::uiGetDevSpecific()
+/*++
+
+Routine Description:
+
+ Gets the HW (!) Device Specific info
+
+Arguments:
+
+ N/A
+
+Return Value:
+
+ UINT (in this example).
+
+--*/
+{
+ return m_uiDevSpecific;
+} // uiGetDevSpecific
+
+//=============================================================================
+void
+CSimpleAudioSampleHW::uiSetDevSpecific
+(
+ _In_ UINT uiDevSpecific
+)
+/*++
+
+Routine Description:
+
+ Sets the HW (!) Device Specific info
+
+Arguments:
+
+ uiDevSpecific - int for this example.
+
+Return Value:
+
+ void
+
+--*/
+{
+ m_uiDevSpecific = uiDevSpecific;
+} // uiSetDevSpecific
+
+
+//=============================================================================
+BOOL
+CSimpleAudioSampleHW::GetMixerMute
+(
+ _In_ ULONG ulNode,
+ _In_ ULONG ulChannel
+)
+/*++
+
+Routine Description:
+
+ Gets the HW (!) mute levels for Simple Audio Sample
+
+Arguments:
+
+ ulNode - topology node id
+
+ ulChannel - which channel are we reading?
+
+Return Value:
+
+ mute setting
+
+--*/
+{
+ UNREFERENCED_PARAMETER(ulChannel);
+
+ if (ulNode < MAX_TOPOLOGY_NODES)
+ {
+ return m_MuteControls[ulNode];
+ }
+
+ return 0;
+} // GetMixerMute
+
+//=============================================================================
+ULONG
+CSimpleAudioSampleHW::GetMixerMux()
+/*++
+
+Routine Description:
+
+ Return the current mux selection
+
+Arguments:
+
+Return Value:
+
+ ULONG
+
+--*/
+{
+ return m_ulMux;
+} // GetMixerMux
+
+//=============================================================================
+LONG
+CSimpleAudioSampleHW::GetMixerVolume
+(
+ _In_ ULONG ulNode,
+ _In_ ULONG ulChannel
+)
+/*++
+
+Routine Description:
+
+ Gets the HW (!) volume for Simple Audio Sample.
+
+Arguments:
+
+ ulNode - topology node id
+
+ ulChannel - which channel are we reading?
+
+Return Value:
+
+ LONG - volume level
+
+--*/
+{
+ UNREFERENCED_PARAMETER(ulChannel);
+
+ if (ulNode < MAX_TOPOLOGY_NODES)
+ {
+ return m_VolumeControls[ulNode];
+ }
+
+ return 0;
+} // GetMixerVolume
+
+//=============================================================================
+LONG
+CSimpleAudioSampleHW::GetMixerPeakMeter
+(
+ _In_ ULONG ulNode,
+ _In_ ULONG ulChannel
+)
+/*++
+
+Routine Description:
+
+ Gets the HW (!) peak meter for Simple Audio Sample.
+
+Arguments:
+
+ ulNode - topology node id
+
+ ulChannel - which channel are we reading?
+
+Return Value:
+
+ LONG - sample peak meter level
+
+--*/
+{
+ UNREFERENCED_PARAMETER(ulChannel);
+
+ if (ulNode < MAX_TOPOLOGY_NODES)
+ {
+ return m_PeakMeterControls[ulNode];
+ }
+
+ return 0;
+} // GetMixerVolume
+
+//=============================================================================
+#pragma code_seg("PAGE")
+void
+CSimpleAudioSampleHW::MixerReset()
+/*++
+
+Routine Description:
+
+ Resets the mixer registers.
+
+Arguments:
+
+Return Value:
+
+ void
+
+--*/
+{
+ PAGED_CODE();
+
+ RtlFillMemory(m_VolumeControls, sizeof(LONG) * MAX_TOPOLOGY_NODES, 0xFF);
+ // Endpoints are not muted by default.
+ RtlZeroMemory(m_MuteControls, sizeof(BOOL) * MAX_TOPOLOGY_NODES);
+
+ for (ULONG i=0; i<MAX_TOPOLOGY_NODES; ++i)
+ {
+ m_PeakMeterControls[i] = PEAKMETER_SIGNED_MAXIMUM/2;
+ }
+
+ // BUGBUG change this depending on the topology
+ m_ulMux = 2;
+} // MixerReset
+#pragma code_seg()
+
+//=============================================================================
+void
+CSimpleAudioSampleHW::SetMixerMute
+(
+ _In_ ULONG ulNode,
+ _In_ ULONG ulChannel,
+ _In_ BOOL fMute
+)
+/*++
+
+Routine Description:
+
+ Sets the HW (!) mute levels for Simple Audio Sample
+
+Arguments:
+
+ ulNode - topology node id
+
+ ulChannel - which channel are we setting?
+
+ fMute - mute flag
+
+Return Value:
+
+ void
+
+--*/
+{
+ UNREFERENCED_PARAMETER(ulChannel);
+
+ if (ulNode < MAX_TOPOLOGY_NODES)
+ {
+ m_MuteControls[ulNode] = fMute;
+ }
+} // SetMixerMute
+
+//=============================================================================
+void
+CSimpleAudioSampleHW::SetMixerMux
+(
+ _In_ ULONG ulNode
+)
+/*++
+
+Routine Description:
+
+ Sets the HW (!) mux selection
+
+Arguments:
+
+ ulNode - topology node id
+
+Return Value:
+
+ void
+
+--*/
+{
+ m_ulMux = ulNode;
+} // SetMixMux
+
+//=============================================================================
+void
+CSimpleAudioSampleHW::SetMixerVolume
+(
+ _In_ ULONG ulNode,
+ _In_ ULONG ulChannel,
+ _In_ LONG lVolume
+)
+/*++
+
+Routine Description:
+
+ Sets the HW (!) volume for Simple Audio Sample.
+
+Arguments:
+
+ ulNode - topology node id
+
+ ulChannel - which channel are we setting?
+
+ lVolume - volume level
+
+Return Value:
+
+ void
+
+--*/
+{
+ UNREFERENCED_PARAMETER(ulChannel);
+
+ if (ulNode < MAX_TOPOLOGY_NODES)
+ {
+ m_VolumeControls[ulNode] = lVolume;
+ }
+} // SetMixerVolume
diff --git a/audio/simpleaudiosample/Source/Utilities/hw.h b/audio/simpleaudiosample/Source/Utilities/hw.h
new file mode 100644
index 00000000..3360c24a
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Utilities/hw.h
@@ -0,0 +1,105 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ hw.h
+
+Abstract:
+
+ Declaration of Simple Audio Sample HW class.
+ Simple Audio Sample HW has an array for storing mixer and volume settings
+ for the topology.
+--*/
+
+#ifndef _SIMPLEAUDIOSAMPLE_HW_H_
+#define _SIMPLEAUDIOSAMPLE_HW_H_
+
+//=============================================================================
+// Defines
+//=============================================================================
+// BUGBUG we should dynamically allocate this...
+#define MAX_TOPOLOGY_NODES 20
+
+//=============================================================================
+// Classes
+//=============================================================================
+///////////////////////////////////////////////////////////////////////////////
+// CSimpleAudioSampleHW
+// This class represents virtual Simple Audio Sample HW. An array representing volume
+// registers and mute registers.
+
+class CSimpleAudioSampleHW
+{
+public:
+protected:
+ BOOL m_MuteControls[MAX_TOPOLOGY_NODES];
+ LONG m_VolumeControls[MAX_TOPOLOGY_NODES];
+ LONG m_PeakMeterControls[MAX_TOPOLOGY_NODES];
+ ULONG m_ulMux; // Mux selection
+ BOOL m_bDevSpecific;
+ INT m_iDevSpecific;
+ UINT m_uiDevSpecific;
+
+private:
+
+public:
+ CSimpleAudioSampleHW();
+
+ void MixerReset();
+ BOOL bGetDevSpecific();
+ void bSetDevSpecific
+ (
+ _In_ BOOL bDevSpecific
+ );
+ INT iGetDevSpecific();
+ void iSetDevSpecific
+ (
+ _In_ INT iDevSpecific
+ );
+ UINT uiGetDevSpecific();
+ void uiSetDevSpecific
+ (
+ _In_ UINT uiDevSpecific
+ );
+ BOOL GetMixerMute
+ (
+ _In_ ULONG ulNode,
+ _In_ ULONG ulChannel
+ );
+ void SetMixerMute
+ (
+ _In_ ULONG ulNode,
+ _In_ ULONG ulChannel,
+ _In_ BOOL fMute
+ );
+ ULONG GetMixerMux();
+ void SetMixerMux
+ (
+ _In_ ULONG ulNode
+ );
+ LONG GetMixerVolume
+ (
+ _In_ ULONG ulNode,
+ _In_ ULONG ulChannel
+ );
+ void SetMixerVolume
+ (
+ _In_ ULONG ulNode,
+ _In_ ULONG ulChannel,
+ _In_ LONG lVolume
+ );
+
+ LONG GetMixerPeakMeter
+ (
+ _In_ ULONG ulNode,
+ _In_ ULONG ulChannel
+ );
+
+protected:
+private:
+};
+typedef CSimpleAudioSampleHW *PCSimpleAudioSampleHW;
+
+#endif // _SIMPLEAUDIOSAMPLE_HW_H_
diff --git a/audio/simpleaudiosample/Source/Utilities/kshelper.cpp b/audio/simpleaudiosample/Source/Utilities/kshelper.cpp
new file mode 100644
index 00000000..e71c6021
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Utilities/kshelper.cpp
@@ -0,0 +1,958 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ kshelper.cpp
+
+Abstract:
+
+ Helper functions for simple audio sample
+--*/
+
+#include "definitions.h"
+
+//4127: conditional expression is constant
+#pragma warning (disable : 4127)
+
+//-----------------------------------------------------------------------------
+#pragma code_seg("PAGE")
+PWAVEFORMATEX
+GetWaveFormatEx
+(
+ _In_ PKSDATAFORMAT pDataFormat
+)
+/*++
+
+Routine Description:
+
+ Returns the waveformatex for known formats.
+
+Arguments:
+
+ pDataFormat - data format.
+
+Return Value:
+
+ waveformatex in DataFormat.
+ NULL for unknown data formats.
+
+--*/
+{
+ PAGED_CODE();
+
+ PWAVEFORMATEX pWfx = NULL;
+
+ // If this is a known dataformat extract the waveformat info.
+ //
+ if
+ (
+ pDataFormat &&
+ ( IsEqualGUIDAligned(pDataFormat->MajorFormat,
+ KSDATAFORMAT_TYPE_AUDIO) &&
+ ( IsEqualGUIDAligned(pDataFormat->Specifier,
+ KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) ||
+ IsEqualGUIDAligned(pDataFormat->Specifier,
+ KSDATAFORMAT_SPECIFIER_DSOUND) ) )
+ )
+ {
+ pWfx = PWAVEFORMATEX(pDataFormat + 1);
+
+ if (IsEqualGUIDAligned(pDataFormat->Specifier,
+ KSDATAFORMAT_SPECIFIER_DSOUND))
+ {
+ PKSDSOUND_BUFFERDESC pwfxds;
+
+ pwfxds = PKSDSOUND_BUFFERDESC(pDataFormat + 1);
+ pWfx = &pwfxds->WaveFormatEx;
+ }
+ }
+
+ return pWfx;
+} // GetWaveFormatEx
+
+//-----------------------------------------------------------------------------
+#pragma code_seg("PAGE")
+NTSTATUS
+ValidatePropertyParams
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG cbValueSize,
+ _In_ ULONG cbInstanceSize /* = 0 */
+)
+/*++
+
+Routine Description:
+
+ Validates property parameters.
+
+Arguments:
+
+ PropertyRequest -
+ cbValueSize -
+ cbInstanceSize -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
+
+ if (PropertyRequest && cbValueSize)
+ {
+ // If the caller is asking for ValueSize.
+ //
+ if (0 == PropertyRequest->ValueSize)
+ {
+ PropertyRequest->ValueSize = cbValueSize;
+ ntStatus = STATUS_BUFFER_OVERFLOW;
+ }
+ // If the caller passed an invalid ValueSize.
+ //
+ else if (PropertyRequest->ValueSize < cbValueSize)
+ {
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ else if (PropertyRequest->InstanceSize < cbInstanceSize)
+ {
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ // If all parameters are OK.
+ //
+ else if (PropertyRequest->ValueSize >= cbValueSize)
+ {
+ if (PropertyRequest->Value)
+ {
+ ntStatus = STATUS_SUCCESS;
+ //
+ // Caller should set ValueSize, if the property
+ // call is successful.
+ //
+ }
+ }
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ // Clear the ValueSize if unsuccessful.
+ //
+ if (PropertyRequest &&
+ STATUS_SUCCESS != ntStatus &&
+ STATUS_BUFFER_OVERFLOW != ntStatus)
+ {
+ PropertyRequest->ValueSize = 0;
+ }
+
+ return ntStatus;
+} // ValidatePropertyParams
+
+//-----------------------------------------------------------------------------
+#pragma code_seg("PAGE")
+NTSTATUS
+SimpleAudioSamplePropertyDispatch
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+ Handles and dispatches a SIMPLEAUDIOSAMPLE_PROPERTY_ITEM.
+
+ Use this as the property handler only if the property item is a
+ SIMPLEAUDIOSAMPLE_PROPERTY_ITEM.
+--*/
+{
+ PAGED_CODE();
+
+ SIMPLEAUDIOSAMPLE_PROPERTY_ITEM* item = (SIMPLEAUDIOSAMPLE_PROPERTY_ITEM*)PropertyRequest->PropertyItem;
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ if (item->SupportHandler != nullptr)
+ {
+ return item->SupportHandler(PropertyRequest);
+ }
+ else
+ {
+ return PropertyHandler_BasicSupport(PropertyRequest, PropertyRequest->PropertyItem->Flags, VT_ILLEGAL);
+ }
+ }
+
+ // Verify instance data size
+ if (PropertyRequest->InstanceSize < item->MinProperty)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ ULONG cbMinSize = item->MinData;
+
+ // Verify value size
+ if (PropertyRequest->ValueSize == 0)
+ {
+ PropertyRequest->ValueSize = cbMinSize;
+ return STATUS_BUFFER_OVERFLOW;
+ }
+ if (PropertyRequest->ValueSize < cbMinSize)
+ {
+ PropertyRequest->ValueSize = 0;
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ if (item->GetHandler != nullptr)
+ {
+ return item->GetHandler(PropertyRequest);
+ }
+ else
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+ }
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ if (item->SetHandler != nullptr)
+ {
+ return item->SetHandler(PropertyRequest);
+ }
+ else
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+ }
+
+ return STATUS_INVALID_DEVICE_REQUEST;
+}
+
+//-----------------------------------------------------------------------------
+#pragma code_seg("PAGE")
+NTSTATUS
+PropertyHandler_BasicSupport
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG Flags,
+ _In_ DWORD PropTypeSetId
+)
+/*++
+
+Routine Description:
+
+ Default basic support handler. Basic processing depends on the size of data.
+ For ULONG it only returns Flags. For KSPROPERTY_DESCRIPTION, the structure
+ is filled.
+
+Arguments:
+
+ PropertyRequest -
+
+ Flags - Support flags.
+
+ PropTypeSetId - PropTypeSetId
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(Flags & KSPROPERTY_TYPE_BASICSUPPORT);
+
+ NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
+
+ if (PropertyRequest->ValueSize >= sizeof(KSPROPERTY_DESCRIPTION))
+ {
+ // if return buffer can hold a KSPROPERTY_DESCRIPTION, return it
+ //
+ PKSPROPERTY_DESCRIPTION PropDesc =
+ PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
+
+ PropDesc->AccessFlags = Flags;
+ PropDesc->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION);
+ if (VT_ILLEGAL != PropTypeSetId)
+ {
+ PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General;
+ PropDesc->PropTypeSet.Id = PropTypeSetId;
+ }
+ else
+ {
+ PropDesc->PropTypeSet.Set = GUID_NULL;
+ PropDesc->PropTypeSet.Id = 0;
+ }
+ PropDesc->PropTypeSet.Flags = 0;
+ PropDesc->MembersListCount = 0;
+ PropDesc->Reserved = 0;
+
+ PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION);
+ ntStatus = STATUS_SUCCESS;
+ }
+ else if (PropertyRequest->ValueSize >= sizeof(ULONG))
+ {
+ // if return buffer can hold a ULONG, return the access flags
+ //
+ *(PULONG(PropertyRequest->Value)) = Flags;
+
+ PropertyRequest->ValueSize = sizeof(ULONG);
+ ntStatus = STATUS_SUCCESS;
+ }
+ else
+ {
+ PropertyRequest->ValueSize = 0;
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ return ntStatus;
+} // PropertyHandler_BasicSupport
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+PropertyHandler_BasicSupportVolume
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG MaxChannels
+)
+/*++
+
+Routine Description:
+
+ Handles BasicSupport for Volume nodes.
+
+Arguments:
+
+ PropertyRequest - property request structure.
+
+ MaxChannels - # of supported channels.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ ULONG cbFullProperty =
+ sizeof(KSPROPERTY_DESCRIPTION) +
+ sizeof(KSPROPERTY_MEMBERSHEADER) +
+ sizeof(KSPROPERTY_STEPPING_LONG) * MaxChannels;
+
+ ASSERT(MaxChannels > 0);
+
+ if (PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION)))
+ {
+ PKSPROPERTY_DESCRIPTION PropDesc =
+ PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
+
+ PropDesc->AccessFlags = KSPROPERTY_TYPE_ALL;
+ PropDesc->DescriptionSize = cbFullProperty;
+ PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General;
+ PropDesc->PropTypeSet.Id = VT_I4;
+ PropDesc->PropTypeSet.Flags = 0;
+ PropDesc->MembersListCount = 1;
+ PropDesc->Reserved = 0;
+
+ // if return buffer can also hold a range description, return it too
+ if(PropertyRequest->ValueSize >= cbFullProperty)
+ {
+ // fill in the members header
+ PKSPROPERTY_MEMBERSHEADER Members =
+ PKSPROPERTY_MEMBERSHEADER(PropDesc + 1);
+
+ Members->MembersFlags = KSPROPERTY_MEMBER_STEPPEDRANGES;
+ Members->MembersSize = sizeof(KSPROPERTY_STEPPING_LONG);
+ Members->MembersCount = MaxChannels;
+ Members->Flags = KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL;
+
+ // fill in the stepped range
+ PKSPROPERTY_STEPPING_LONG Range =
+ PKSPROPERTY_STEPPING_LONG(Members + 1);
+
+ for (ULONG i=0; i<MaxChannels; ++i)
+ {
+ Range[i].Bounds.SignedMaximum = VOLUME_SIGNED_MAXIMUM; // 0 dB
+ Range[i].Bounds.SignedMinimum = VOLUME_SIGNED_MINIMUM; // -96 dB
+ Range[i].SteppingDelta = VOLUME_STEPPING_DELTA; // .5 dB
+ Range[i].Reserved = 0;
+ }
+
+ // set the return value size
+ PropertyRequest->ValueSize = cbFullProperty;
+ }
+ else
+ {
+ PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION);
+ }
+ }
+ else if(PropertyRequest->ValueSize >= sizeof(ULONG))
+ {
+ // if return buffer can hold a ULONG, return the access flags
+ PULONG AccessFlags = PULONG(PropertyRequest->Value);
+
+ PropertyRequest->ValueSize = sizeof(ULONG);
+ *AccessFlags = KSPROPERTY_TYPE_ALL;
+ }
+ else
+ {
+ PropertyRequest->ValueSize = 0;
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ return ntStatus;
+} // PropertyHandlerBasicSupportVolume
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+PropertyHandler_BasicSupportMute
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG MaxChannels
+)
+/*++
+
+Routine Description:
+
+ Handles BasicSupport for Mute nodes.
+
+Arguments:
+
+ PropertyRequest - property request structure.
+
+ MaxChannels - # of supported channels.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ ULONG cbFullProperty =
+ sizeof(KSPROPERTY_DESCRIPTION) +
+ sizeof(KSPROPERTY_MEMBERSHEADER) +
+ sizeof(KSPROPERTY_STEPPING_LONG) * MaxChannels;
+
+ ASSERT(MaxChannels > 0);
+
+ if (PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION)))
+ {
+ PKSPROPERTY_DESCRIPTION PropDesc =
+ PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
+
+ PropDesc->AccessFlags = KSPROPERTY_TYPE_ALL;
+ PropDesc->DescriptionSize = cbFullProperty;
+ PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General;
+ PropDesc->PropTypeSet.Id = VT_BOOL;
+ PropDesc->PropTypeSet.Flags = 0;
+ PropDesc->MembersListCount = 1;
+ PropDesc->Reserved = 0;
+
+ // if return buffer can also hold a range description, return it too
+ if(PropertyRequest->ValueSize >= cbFullProperty)
+ {
+ // fill in the members header
+ PKSPROPERTY_MEMBERSHEADER Members =
+ PKSPROPERTY_MEMBERSHEADER(PropDesc + 1);
+
+ Members->MembersFlags = KSPROPERTY_MEMBER_STEPPEDRANGES;
+ Members->MembersSize = sizeof(KSPROPERTY_STEPPING_LONG);
+ Members->MembersCount = MaxChannels;
+ Members->Flags = KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL;
+
+ // fill in the stepped range
+ PKSPROPERTY_STEPPING_LONG Range =
+ PKSPROPERTY_STEPPING_LONG(Members + 1);
+
+ for (ULONG i=0; i<MaxChannels; ++i)
+ {
+ Range[i].Bounds.SignedMaximum = 1; // true
+ Range[i].Bounds.SignedMinimum = 0; // false
+ Range[i].SteppingDelta = 1; // false <- -> true
+ Range[i].Reserved = 0;
+ }
+
+ // set the return value size
+ PropertyRequest->ValueSize = cbFullProperty;
+ }
+ else
+ {
+ PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION);
+ }
+ }
+ else if(PropertyRequest->ValueSize >= sizeof(ULONG))
+ {
+ // if return buffer can hold a ULONG, return the access flags
+ PULONG AccessFlags = PULONG(PropertyRequest->Value);
+
+ PropertyRequest->ValueSize = sizeof(ULONG);
+ *AccessFlags = KSPROPERTY_TYPE_ALL;
+ }
+ else
+ {
+ PropertyRequest->ValueSize = 0;
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ return ntStatus;
+} // PropertyHandlerBasicSupportVolume
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+PropertyHandler_BasicSupportPeakMeter2
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG MaxChannels
+)
+/*++
+
+Routine Description:
+
+ Handles BasicSupport for peak meter nodes.
+
+Arguments:
+
+ PropertyRequest - property request structure.
+
+ MaxChannels - # of supported channels.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ ULONG cbFullProperty =
+ sizeof(KSPROPERTY_DESCRIPTION) +
+ sizeof(KSPROPERTY_MEMBERSHEADER) +
+ sizeof(KSPROPERTY_STEPPING_LONG) * MaxChannels;
+
+ ASSERT(MaxChannels > 0);
+
+ if (PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION)))
+ {
+ PKSPROPERTY_DESCRIPTION PropDesc =
+ PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
+
+ PropDesc->AccessFlags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT;
+ PropDesc->DescriptionSize = cbFullProperty;
+ PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General;
+ PropDesc->PropTypeSet.Id = VT_I4;
+ PropDesc->PropTypeSet.Flags = 0;
+ PropDesc->MembersListCount = 1;
+ PropDesc->Reserved = 0;
+
+ // if return buffer can also hold a range description, return it too
+ if(PropertyRequest->ValueSize >= cbFullProperty)
+ {
+ // fill in the members header
+ PKSPROPERTY_MEMBERSHEADER Members =
+ PKSPROPERTY_MEMBERSHEADER(PropDesc + 1);
+
+ Members->MembersFlags = KSPROPERTY_MEMBER_STEPPEDRANGES;
+ Members->MembersSize = sizeof(KSPROPERTY_STEPPING_LONG);
+ Members->MembersCount = MaxChannels;
+ Members->Flags = KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL;
+
+ // fill in the stepped range
+ PKSPROPERTY_STEPPING_LONG Range =
+ PKSPROPERTY_STEPPING_LONG(Members + 1);
+
+ for (ULONG i=0; i<MaxChannels; ++i)
+ {
+ Range[i].Bounds.SignedMaximum = PEAKMETER_SIGNED_MAXIMUM;
+ Range[i].Bounds.SignedMinimum = PEAKMETER_SIGNED_MINIMUM;
+ Range[i].SteppingDelta = PEAKMETER_STEPPING_DELTA;
+ Range[i].Reserved = 0;
+ }
+
+ // set the return value size
+ PropertyRequest->ValueSize = cbFullProperty;
+ }
+ else
+ {
+ PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION);
+ }
+ }
+ else if(PropertyRequest->ValueSize >= sizeof(ULONG))
+ {
+ // if return buffer can hold a ULONG, return the access flags
+ PULONG AccessFlags = PULONG(PropertyRequest->Value);
+
+ PropertyRequest->ValueSize = sizeof(ULONG);
+ *AccessFlags = KSPROPERTY_TYPE_ALL;
+ }
+ else
+ {
+ PropertyRequest->ValueSize = 0;
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ return ntStatus;
+} // PropertyHandlerBasicSupportVolume
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+PropertyHandler_CpuResources
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Processes KSPROPERTY_AUDIO_CPURESOURCES
+
+Arguments:
+
+ PropertyRequest - property request structure.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[%s]",__FUNCTION__));
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ ntStatus = ValidatePropertyParams(PropertyRequest, sizeof(ULONG));
+ if (NT_SUCCESS(ntStatus))
+ {
+ *(PULONG(PropertyRequest->Value)) = KSAUDIO_CPU_RESOURCES_NOT_HOST_CPU;
+ PropertyRequest->ValueSize = sizeof(ULONG);
+ }
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ntStatus =
+ PropertyHandler_BasicSupport
+ (
+ PropertyRequest,
+ KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
+ VT_UI4
+ );
+ }
+
+ return ntStatus;
+} // PropertyHandlerCpuResources
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+PropertyHandler_Volume
+(
+ _In_ PADAPTERCOMMON AdapterCommon,
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG MaxChannels
+)
+/*++
+
+Routine Description:
+
+ Property handler for KSPROPERTY_AUDIO_VOLUMELEVEL
+
+Arguments:
+
+ AdapterCommon - interface to the common adapter object.
+
+ PropertyRequest - property request structure.
+
+ MaxChannels - # of supported channels.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[%s]",__FUNCTION__));
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ ULONG ulChannel;
+ PLONG plVolume;
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ntStatus = PropertyHandler_BasicSupportVolume(
+ PropertyRequest,
+ MaxChannels);
+ }
+ else
+ {
+ ntStatus =
+ ValidatePropertyParams
+ (
+ PropertyRequest,
+ sizeof(LONG), // volume value is a LONG
+ sizeof(ULONG) // instance is the channel number
+ );
+ if (NT_SUCCESS(ntStatus))
+ {
+ ulChannel = * (PULONG (PropertyRequest->Instance));
+ plVolume = PLONG (PropertyRequest->Value);
+
+ if (ulChannel >= MaxChannels &&
+ ulChannel != ALL_CHANNELS_ID)
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ *plVolume =
+ AdapterCommon->MixerVolumeRead
+ (
+ PropertyRequest->Node,
+ ulChannel == ALL_CHANNELS_ID ? 0 : ulChannel
+ );
+ PropertyRequest->ValueSize = sizeof(ULONG);
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ if (ALL_CHANNELS_ID == ulChannel)
+ {
+ for (ULONG i=0; i<ulChannel; ++i)
+ {
+ AdapterCommon->MixerVolumeWrite
+ (
+ PropertyRequest->Node,
+ i,
+ VOLUME_NORMALIZE_IN_RANGE(*plVolume)
+ );
+ }
+ }
+ else
+ {
+ AdapterCommon->MixerVolumeWrite
+ (
+ PropertyRequest->Node,
+ ulChannel,
+ VOLUME_NORMALIZE_IN_RANGE(*plVolume)
+ );
+ }
+ }
+ }
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_TERSE, ("[%s - ntStatus=0x%08x]",__FUNCTION__,ntStatus));
+ }
+ }
+
+ return ntStatus;
+} // PropertyHandlerVolume
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+PropertyHandler_Mute
+(
+ _In_ PADAPTERCOMMON AdapterCommon,
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG MaxChannels
+)
+/*++
+
+Routine Description:
+
+ Property handler for KSPROPERTY_AUDIO_MUTE
+
+Arguments:
+
+ AdapterCommon - interface to the common adapter object.
+
+ PropertyRequest - property request structure.
+
+ MaxChannels - # of supported channels.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[%s]",__FUNCTION__));
+
+ NTSTATUS ntStatus;
+ ULONG ulChannel;
+ PBOOL pfMute;
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ntStatus = PropertyHandler_BasicSupportMute(
+ PropertyRequest,
+ MaxChannels);
+ }
+ else
+ {
+ ntStatus =
+ ValidatePropertyParams
+ (
+ PropertyRequest,
+ sizeof(BOOL),
+ sizeof(ULONG)
+ );
+ if (NT_SUCCESS(ntStatus))
+ {
+ ulChannel = * (PULONG (PropertyRequest->Instance));
+ pfMute = PBOOL (PropertyRequest->Value);
+
+ if (ulChannel >= MaxChannels &&
+ ulChannel != ALL_CHANNELS_ID)
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ *pfMute =
+ AdapterCommon->MixerMuteRead
+ (
+ PropertyRequest->Node,
+ ulChannel == ALL_CHANNELS_ID ? 0 : ulChannel
+ );
+ PropertyRequest->ValueSize = sizeof(BOOL);
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ if (ALL_CHANNELS_ID == ulChannel)
+ {
+ for (ULONG i=0; i<ulChannel; ++i)
+ {
+ AdapterCommon->MixerMuteWrite
+ (
+ PropertyRequest->Node,
+ i,
+ (*pfMute) ? TRUE : FALSE
+ );
+ }
+ }
+ else
+ {
+ AdapterCommon->MixerMuteWrite
+ (
+ PropertyRequest->Node,
+ ulChannel,
+ (*pfMute) ? TRUE : FALSE
+ );
+ }
+ }
+ }
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_TERSE, ("[%s - ntStatus=0x%08x]",__FUNCTION__,ntStatus));
+ }
+ }
+
+ return ntStatus;
+} // PropertyHandlerMute
+
+//=============================================================================
+#pragma code_seg("PAGE")
+NTSTATUS
+PropertyHandler_PeakMeter2
+(
+ _In_ PADAPTERCOMMON AdapterCommon,
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG MaxChannels
+)
+/*++
+
+Routine Description:
+
+ Property handler for KSPROPERTY_AUDIO_PEAKMETER2
+
+Arguments:
+
+ AdapterCommon - interface to the common adapter object.
+
+ PropertyRequest - property request structure.
+
+ MaxChannels - # of supported channels.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[%s]",__FUNCTION__));
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ ULONG ulChannel;
+ PLONG plSample;
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ntStatus = PropertyHandler_BasicSupportPeakMeter2(
+ PropertyRequest,
+ MaxChannels);
+ }
+ else
+ {
+ ntStatus =
+ ValidatePropertyParams
+ (
+ PropertyRequest,
+ sizeof(LONG), // sample value is a LONG
+ sizeof(ULONG) // instance is the channel number
+ );
+ if (NT_SUCCESS(ntStatus))
+ {
+ ulChannel = * (PULONG (PropertyRequest->Instance));
+ plSample = PLONG (PropertyRequest->Value);
+
+ if (ulChannel >= MaxChannels &&
+ ulChannel != ALL_CHANNELS_ID)
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ *plSample =
+ PEAKMETER_NORMALIZE_IN_RANGE(
+ AdapterCommon->MixerPeakMeterRead
+ (
+ PropertyRequest->Node,
+ ulChannel == ALL_CHANNELS_ID ? 0 : ulChannel
+ ));
+
+ PropertyRequest->ValueSize = sizeof(ULONG);
+ }
+ }
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_TERSE, ("[%s - ntStatus=0x%08x]",__FUNCTION__,ntStatus));
+ }
+ }
+
+ return ntStatus;
+} // PropertyHandlerVolume
+
diff --git a/audio/simpleaudiosample/Source/Utilities/savedata.cpp b/audio/simpleaudiosample/Source/Utilities/savedata.cpp
new file mode 100644
index 00000000..7b2a11e9
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Utilities/savedata.cpp
@@ -0,0 +1,1033 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ savedata.cpp
+
+Abstract:
+
+ Implementation of Simple Audio Sample data saving class.
+
+ To save the playback data to disk, this class maintains a circular data
+ buffer, associated frame structures and worker items to save frames to
+ disk.
+ Each frame structure represents a portion of buffer. When that portion
+ of frame is full, a workitem is scheduled to save it to disk.
+--*/
+#pragma warning (disable : 4127)
+#pragma warning (disable : 26165)
+
+#include "definitions.h"
+#include "savedata.h"
+#include <ntstrsafe.h> // This is for using RtlStringcbPrintf
+
+#define SAVEDATA_POOLTAG 'TDVS'
+#define SAVEDATA_POOLTAG1 '1DVS'
+#define SAVEDATA_POOLTAG2 '2DVS'
+#define SAVEDATA_POOLTAG3 '3DVS'
+#define SAVEDATA_POOLTAG4 '4DVS'
+#define SAVEDATA_POOLTAG5 '5DVS'
+#define SAVEDATA_POOLTAG6 '6DVS'
+#define SAVEDATA_POOLTAG7 '7DVS'
+
+//=============================================================================
+// Defines
+//=============================================================================
+#define RIFF_TAG 0x46464952;
+#define WAVE_TAG 0x45564157;
+#define FMT__TAG 0x20746D66;
+#define DATA_TAG 0x61746164;
+
+#define DEFAULT_FRAME_COUNT 4
+#define DEFAULT_FRAME_SIZE PAGE_SIZE * 4
+#define DEFAULT_BUFFER_SIZE DEFAULT_FRAME_SIZE * DEFAULT_FRAME_COUNT
+
+#define DEFAULT_FILE_NAME L"\\DosDevices\\C:\\STREAM"
+#define OSDATA_FILE_NAME L"\\DosDevices\\O:\\STREAM"
+#define OFFLOAD_FILE_NAME L"OFFLOAD"
+#define HOST_FILE_NAME L"HOST"
+
+#define MAX_WORKER_ITEM_COUNT 15
+
+//=============================================================================
+// Statics
+//=============================================================================
+ULONG CSaveData::m_ulStreamId = 0;
+
+#pragma code_seg("PAGE")
+//=============================================================================
+// CSaveData
+//=============================================================================
+
+//=============================================================================
+CSaveData::CSaveData()
+: m_pDataBuffer(NULL),
+ m_FileHandle(NULL),
+ m_ulFrameCount(DEFAULT_FRAME_COUNT),
+ m_ulBufferSize(DEFAULT_BUFFER_SIZE),
+ m_ulFrameSize(DEFAULT_FRAME_SIZE),
+ m_ulBufferOffset(0),
+ m_ulFrameIndex(0),
+ m_fFrameUsed(NULL),
+ m_waveFormat(NULL),
+ m_pFilePtr(NULL),
+ m_fWriteDisabled(FALSE),
+ m_bInitialized(FALSE)
+{
+ PAGED_CODE();
+
+ m_FileHeader.dwRiff = RIFF_TAG;
+ m_FileHeader.dwFileSize = 0;
+ m_FileHeader.dwWave = WAVE_TAG;
+ m_FileHeader.dwFormat = FMT__TAG;
+ m_FileHeader.dwFormatLength = sizeof(WAVEFORMATEX);
+
+ m_DataHeader.dwData = DATA_TAG;
+ m_DataHeader.dwDataLength = 0;
+
+ RtlZeroMemory(&m_objectAttributes, sizeof(m_objectAttributes));
+} // CSaveData
+
+//=============================================================================
+CSaveData::~CSaveData()
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CSaveData::~CSaveData]"));
+
+ // Update the wave header in data file with real file size.
+ //
+ if(m_pFilePtr)
+ {
+ m_FileHeader.dwFileSize =
+ (DWORD) m_pFilePtr->QuadPart - 2 * sizeof(DWORD);
+ m_DataHeader.dwDataLength = (DWORD) m_pFilePtr->QuadPart -
+ sizeof(m_FileHeader) -
+ m_FileHeader.dwFormatLength -
+ sizeof(m_DataHeader);
+
+ if (STATUS_SUCCESS == KeWaitForSingleObject
+ (
+ &m_FileSync,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ ))
+ {
+ if (NT_SUCCESS(FileOpen(FALSE)))
+ {
+ FileWriteHeader();
+
+ FileClose();
+ }
+
+ KeReleaseMutex(&m_FileSync, FALSE);
+ }
+ }
+
+ if (m_waveFormat)
+ {
+ ExFreePoolWithTag(m_waveFormat, SAVEDATA_POOLTAG1);
+ m_waveFormat = NULL;
+ }
+
+ if (m_fFrameUsed)
+ {
+ ExFreePoolWithTag(m_fFrameUsed, SAVEDATA_POOLTAG2);
+ m_fFrameUsed = NULL;
+ // NOTE : Do not release m_pFilePtr.
+ }
+
+ if (m_FileName.Buffer)
+ {
+ ExFreePoolWithTag(m_FileName.Buffer, SAVEDATA_POOLTAG3);
+ m_FileName.Buffer = NULL;
+ }
+
+ if (m_pDataBuffer)
+ {
+ ExFreePoolWithTag(m_pDataBuffer, SAVEDATA_POOLTAG4);
+ m_pDataBuffer = NULL;
+ }
+} // CSaveData
+
+//=============================================================================
+void
+CSaveData::DestroyWorkItems
+(
+ void
+)
+{
+ PAGED_CODE();
+
+ if (m_pWorkItems)
+ {
+ for (int i = 0; i < MAX_WORKER_ITEM_COUNT; i++)
+ {
+ if (m_pWorkItems[i].WorkItem!=NULL)
+ {
+ IoFreeWorkItem(m_pWorkItems[i].WorkItem);
+ m_pWorkItems[i].WorkItem = NULL;
+ }
+ }
+ ExFreePoolWithTag(m_pWorkItems, SAVEDATA_POOLTAG);
+ m_pWorkItems = NULL;
+ }
+
+} // DestroyWorkItems
+
+//=============================================================================
+void
+CSaveData::Disable
+(
+ _In_ BOOL fDisable
+)
+{
+ PAGED_CODE();
+
+ m_fWriteDisabled = fDisable;
+} // Disable
+
+//=============================================================================
+NTSTATUS
+CSaveData::FileClose(void)
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (m_FileHandle)
+ {
+ ntStatus = ZwClose(m_FileHandle);
+ m_FileHandle = NULL;
+ }
+
+ return ntStatus;
+} // FileClose
+
+//=============================================================================
+NTSTATUS
+CSaveData::FileOpen
+(
+ _In_ BOOL fOverWrite
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ IO_STATUS_BLOCK ioStatusBlock;
+
+ if( FALSE == m_bInitialized )
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ if(!m_FileHandle)
+ {
+ ntStatus =
+ ZwCreateFile
+ (
+ &m_FileHandle,
+ GENERIC_WRITE | SYNCHRONIZE,
+ &m_objectAttributes,
+ &ioStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ 0,
+ fOverWrite ? FILE_OVERWRITE_IF : FILE_OPEN_IF,
+ FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0
+ );
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_TERSE, ("[CSaveData::FileOpen : Error opening data file]"));
+ }
+ }
+
+ return ntStatus;
+} // FileOpen
+
+//=============================================================================
+NTSTATUS
+CSaveData::FileWrite
+(
+ _In_reads_bytes_(ulDataSize) PBYTE pData,
+ _In_ ULONG ulDataSize
+)
+{
+ PAGED_CODE();
+
+ ASSERT(pData);
+ ASSERT(m_pFilePtr);
+
+ NTSTATUS ntStatus;
+
+ if (m_FileHandle)
+ {
+ IO_STATUS_BLOCK ioStatusBlock;
+
+ ntStatus = ZwWriteFile( m_FileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &ioStatusBlock,
+ pData,
+ ulDataSize,
+ m_pFilePtr,
+ NULL);
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ ASSERT(ioStatusBlock.Information == ulDataSize);
+
+ m_pFilePtr->QuadPart += ulDataSize;
+ }
+ else
+ {
+ DPF(D_TERSE, ("[CSaveData::FileWrite : WriteFileError]"));
+ }
+ }
+ else
+ {
+ DPF(D_TERSE, ("[CSaveData::FileWrite : File not open]"));
+ ntStatus = STATUS_INVALID_HANDLE;
+ }
+
+ return ntStatus;
+} // FileWrite
+
+//=============================================================================
+NTSTATUS
+CSaveData::FileWriteHeader(void)
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus;
+
+ if (m_FileHandle && m_waveFormat)
+ {
+ IO_STATUS_BLOCK ioStatusBlock;
+
+ m_pFilePtr->QuadPart = 0;
+
+ m_FileHeader.dwFormatLength = (m_waveFormat->wFormatTag == WAVE_FORMAT_PCM) ?
+ sizeof( PCMWAVEFORMAT ) :
+ sizeof( WAVEFORMATEX ) + m_waveFormat->cbSize;
+
+ ntStatus = ZwWriteFile( m_FileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &ioStatusBlock,
+ &m_FileHeader,
+ sizeof(m_FileHeader),
+ m_pFilePtr,
+ NULL);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_TERSE, ("[CSaveData::FileWriteHeader : Write File Header Error]"));
+ }
+
+ m_pFilePtr->QuadPart += sizeof(m_FileHeader);
+
+ ntStatus = ZwWriteFile( m_FileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &ioStatusBlock,
+ m_waveFormat,
+ m_FileHeader.dwFormatLength,
+ m_pFilePtr,
+ NULL);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_TERSE, ("[CSaveData::FileWriteHeader : Write Format Error]"));
+ }
+
+ m_pFilePtr->QuadPart += m_FileHeader.dwFormatLength;
+
+ ntStatus = ZwWriteFile( m_FileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &ioStatusBlock,
+ &m_DataHeader,
+ sizeof(m_DataHeader),
+ m_pFilePtr,
+ NULL);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_TERSE, ("[CSaveData::FileWriteHeader : Write Data Header Error]"));
+ }
+
+ m_pFilePtr->QuadPart += sizeof(m_DataHeader);
+ }
+ else
+ {
+ DPF(D_TERSE, ("[CSaveData::FileWriteHeader : File not open]"));
+ ntStatus = STATUS_INVALID_HANDLE;
+ }
+
+ return ntStatus;
+} // FileWriteHeader
+NTSTATUS
+CSaveData::SetDeviceObject
+(
+ _In_ PDEVICE_OBJECT DeviceObject
+)
+{
+ PAGED_CODE();
+
+ ASSERT(DeviceObject);
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ m_pDeviceObject = DeviceObject;
+ return ntStatus;
+}
+
+PDEVICE_OBJECT
+CSaveData::GetDeviceObject
+(
+ void
+)
+{
+ PAGED_CODE();
+
+ return m_pDeviceObject;
+}
+
+#pragma code_seg()
+//=============================================================================
+PSAVEWORKER_PARAM
+CSaveData::GetNewWorkItem
+(
+ void
+)
+{
+ LARGE_INTEGER timeOut = { 0 };
+ NTSTATUS ntStatus;
+
+ for (int i = 0; i < MAX_WORKER_ITEM_COUNT; i++)
+ {
+ ntStatus =
+ KeWaitForSingleObject
+ (
+ &m_pWorkItems[i].EventDone,
+ Executive,
+ KernelMode,
+ FALSE,
+ &timeOut
+ );
+ if (STATUS_SUCCESS == ntStatus)
+ {
+ if (m_pWorkItems[i].WorkItem)
+ return &(m_pWorkItems[i]);
+ else
+ return NULL;
+ }
+ }
+
+ return NULL;
+} // GetNewWorkItem
+#pragma code_seg("PAGE")
+
+//=============================================================================
+NTSTATUS
+CSaveData::Initialize
+(
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ WCHAR szTemp[MAX_PATH];
+ size_t cLen;
+ OBJECT_ATTRIBUTES objectAttributes;
+ UNICODE_STRING osDataVolumeString;
+ HANDLE osDataFileHandle = NULL;
+ IO_STATUS_BLOCK ioStatusBlock;
+
+ DPF_ENTER(("[CSaveData::Initialize]"));
+
+ m_ulStreamId++;
+
+ // Probe if OSData volume exists.
+ //
+ RtlStringCchPrintfW(szTemp, MAX_PATH, L"%s_probe.txt", OSDATA_FILE_NAME);
+ RtlInitUnicodeString(&osDataVolumeString, szTemp);
+ InitializeObjectAttributes
+ (
+ &objectAttributes,
+ &osDataVolumeString,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL
+ );
+
+ ntStatus =
+ ZwCreateFile
+ (
+ &osDataFileHandle,
+ GENERIC_WRITE | SYNCHRONIZE,
+ &objectAttributes,
+ &ioStatusBlock,
+ NULL,
+ FILE_ATTRIBUTE_NORMAL,
+ 0,
+ FILE_OVERWRITE_IF,
+ FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0
+ );
+ if (NT_SUCCESS(ntStatus))
+ {
+ ZwClose(osDataFileHandle);
+ }
+
+ // Allocate data file name.
+ //
+ RtlStringCchPrintfW(szTemp, MAX_PATH, L"%s_%s_%d.wav", NT_SUCCESS(ntStatus) ? OSDATA_FILE_NAME : DEFAULT_FILE_NAME, HOST_FILE_NAME, m_ulStreamId);
+ m_FileName.Length = 0;
+ ntStatus = RtlStringCchLengthW (szTemp, sizeof(szTemp)/sizeof(szTemp[0]), &cLen);
+ if (NT_SUCCESS(ntStatus))
+ {
+ m_FileName.MaximumLength = (USHORT)((cLen * sizeof(WCHAR)) + sizeof(WCHAR));//convert to wchar and add room for NULL
+ m_FileName.Buffer = (PWSTR)
+ ExAllocatePool2
+ (
+ POOL_FLAG_PAGED,
+ m_FileName.MaximumLength,
+ SAVEDATA_POOLTAG3
+ );
+ if (!m_FileName.Buffer)
+ {
+ DPF(D_TERSE, ("[Could not allocate memory for FileName]"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ // Allocate memory for data buffer.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ RtlStringCbCopyW(m_FileName.Buffer, m_FileName.MaximumLength, szTemp);
+ m_FileName.Length = (USHORT)wcslen(m_FileName.Buffer) * sizeof(WCHAR);
+ DPF(D_BLAB, ("[New DataFile -- %S", m_FileName.Buffer));
+
+ m_pDataBuffer = (PBYTE)
+ ExAllocatePool2
+ (
+ POOL_FLAG_NON_PAGED,
+ m_ulBufferSize,
+ SAVEDATA_POOLTAG4
+ );
+ if (!m_pDataBuffer)
+ {
+ DPF(D_TERSE, ("[Could not allocate memory for Saving Data]"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ // Allocate memory for frame usage flags and m_pFilePtr.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ m_fFrameUsed = (PBOOL)
+ ExAllocatePool2
+ (
+ POOL_FLAG_NON_PAGED,
+ m_ulFrameCount * sizeof(BOOL) +
+ sizeof(LARGE_INTEGER),
+ SAVEDATA_POOLTAG2
+ );
+ if (!m_fFrameUsed)
+ {
+ DPF(D_TERSE, ("[Could not allocate memory for frame flags]"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ // Initialize the spinlock to synchronize access to the frames
+ //
+ KeInitializeSpinLock ( &m_FrameInUseSpinLock ) ;
+
+ // Initialize the file mutex
+ //
+ KeInitializeMutex( &m_FileSync, 1 ) ;
+
+ // Open the data file.
+ //
+ if (NT_SUCCESS(ntStatus))
+ {
+ // m_fFrameUsed has additional memory to hold m_pFilePtr
+ //
+ m_pFilePtr = (PLARGE_INTEGER)
+ (((PBYTE) m_fFrameUsed) + m_ulFrameCount * sizeof(BOOL));
+
+ // Create data file.
+ InitializeObjectAttributes
+ (
+ &m_objectAttributes,
+ &m_FileName,
+ OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL
+ );
+
+ m_bInitialized = TRUE;
+
+ // Write wave header information to data file.
+ ntStatus = KeWaitForSingleObject
+ (
+ &m_FileSync,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ if (STATUS_SUCCESS == ntStatus)
+ {
+ ntStatus = FileOpen(TRUE);
+ if (NT_SUCCESS(ntStatus))
+ {
+ ntStatus = FileWriteHeader();
+
+ FileClose();
+ }
+
+ KeReleaseMutex( &m_FileSync, FALSE );
+ }
+ }
+
+ return ntStatus;
+} // Initialize
+
+//=============================================================================
+NTSTATUS
+CSaveData::InitializeWorkItems
+(
+ _In_ PDEVICE_OBJECT DeviceObject
+)
+{
+ PAGED_CODE();
+
+ ASSERT(DeviceObject);
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ DPF_ENTER(("[CSaveData::InitializeWorkItems]"));
+
+ if (m_pWorkItems != NULL)
+ {
+ return ntStatus;
+ }
+
+ m_pWorkItems = (PSAVEWORKER_PARAM)
+ ExAllocatePool2
+ (
+ POOL_FLAG_NON_PAGED,
+ sizeof(SAVEWORKER_PARAM) * MAX_WORKER_ITEM_COUNT,
+ SAVEDATA_POOLTAG
+ );
+ if (m_pWorkItems)
+ {
+ for (int i = 0; i < MAX_WORKER_ITEM_COUNT; i++)
+ {
+
+ m_pWorkItems[i].WorkItem = IoAllocateWorkItem(DeviceObject);
+ if(m_pWorkItems[i].WorkItem == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ KeInitializeEvent
+ (
+ &m_pWorkItems[i].EventDone,
+ NotificationEvent,
+ TRUE
+ );
+ }
+ }
+ else
+ {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ return ntStatus;
+} // InitializeWorkItems
+
+//=============================================================================
+
+IO_WORKITEM_ROUTINE SaveFrameWorkerCallback;
+
+VOID
+SaveFrameWorkerCallback
+(
+ _In_ PDEVICE_OBJECT pDeviceObject,
+ _In_opt_ PVOID Context
+)
+{
+ UNREFERENCED_PARAMETER(pDeviceObject);
+
+ PAGED_CODE();
+
+ ASSERT(Context);
+
+ PSAVEWORKER_PARAM pParam = (PSAVEWORKER_PARAM) Context;
+ PCSaveData pSaveData;
+
+ if (NULL == pParam)
+ {
+ // This is completely unexpected, assert here.
+ //
+ ASSERT(pParam);
+ return;
+ }
+
+ DPF(D_VERBOSE, ("[SaveFrameWorkerCallback], %d", pParam->ulFrameNo));
+
+ ASSERT(pParam->pSaveData);
+ ASSERT(pParam->pSaveData->m_fFrameUsed);
+
+ if (pParam->WorkItem)
+ {
+ pSaveData = pParam->pSaveData;
+
+ if (STATUS_SUCCESS == KeWaitForSingleObject
+ (
+ &pSaveData->m_FileSync,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ ))
+ {
+ if (NT_SUCCESS(pSaveData->FileOpen(FALSE)))
+ {
+ pSaveData->FileWrite(pParam->pData, pParam->ulDataSize);
+ pSaveData->FileClose();
+ }
+ InterlockedExchange( (LONG *)&(pSaveData->m_fFrameUsed[pParam->ulFrameNo]), FALSE );
+
+ KeReleaseMutex( &pSaveData->m_FileSync, FALSE );
+ }
+ }
+
+ KeSetEvent(&pParam->EventDone, 0, FALSE);
+} // SaveFrameWorkerCallback
+
+//=============================================================================
+NTSTATUS
+CSaveData::SetDataFormat
+(
+ _In_ PKSDATAFORMAT pDataFormat
+)
+{
+ PAGED_CODE();
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ DPF_ENTER(("[CSaveData::SetDataFormat]"));
+
+ ASSERT(pDataFormat);
+
+ PWAVEFORMATEX pwfx = NULL;
+
+ if (IsEqualGUIDAligned(pDataFormat->Specifier,
+ KSDATAFORMAT_SPECIFIER_DSOUND))
+ {
+ pwfx =
+ &(((PKSDATAFORMAT_DSOUND) pDataFormat)->BufferDesc.WaveFormatEx);
+ }
+ else if (IsEqualGUIDAligned(pDataFormat->Specifier,
+ KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
+ {
+ pwfx = &((PKSDATAFORMAT_WAVEFORMATEX) pDataFormat)->WaveFormatEx;
+ }
+
+ if (pwfx)
+ {
+ // Free the previously allocated waveformat
+ if (m_waveFormat)
+ {
+ ExFreePoolWithTag(m_waveFormat, SAVEDATA_POOLTAG1);
+ }
+
+ m_waveFormat = (PWAVEFORMATEX)
+ ExAllocatePool2
+ (
+ POOL_FLAG_NON_PAGED,
+ (pwfx->wFormatTag == WAVE_FORMAT_PCM) ?
+ sizeof( PCMWAVEFORMAT ) :
+ sizeof( WAVEFORMATEX ) + pwfx->cbSize,
+ SAVEDATA_POOLTAG1
+ );
+
+ if(m_waveFormat)
+ {
+ RtlCopyMemory( m_waveFormat,
+ pwfx,
+ (pwfx->wFormatTag == WAVE_FORMAT_PCM) ?
+ sizeof( PCMWAVEFORMAT ) :
+ sizeof( WAVEFORMATEX ) + pwfx->cbSize);
+ }
+ else
+ {
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ return ntStatus;
+} // SetDataFormat
+
+//=============================================================================
+NTSTATUS
+CSaveData::SetMaxWriteSize
+(
+ _In_ ULONG ulMaxWriteSize
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ ULONG bufferSize = 0;
+ PBYTE buffer = NULL;
+
+ DPF_ENTER(("[CSaveData::SetMaxWriteSize]"));
+
+ //
+ // Compute new buffer size.
+ //
+ ntStatus = RtlULongMult(ulMaxWriteSize, DEFAULT_FRAME_COUNT, &bufferSize);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ DPF(D_TERSE, ("[Could not allocate memory for Saving Data, MaxWriteSize %u is too big]", ulMaxWriteSize));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Alloc memory for buffer.
+ //
+ buffer = (PBYTE)
+ ExAllocatePool2
+ (
+ POOL_FLAG_NON_PAGED,
+ bufferSize,
+ SAVEDATA_POOLTAG4
+ );
+ if (!buffer)
+ {
+ DPF(D_TERSE, ("[Could not allocate memory for Saving Data]"));
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Free old one.
+ //
+ if (m_pDataBuffer)
+ {
+ ExFreePoolWithTag(m_pDataBuffer, SAVEDATA_POOLTAG4);
+ m_pDataBuffer = NULL;
+ }
+
+ //
+ // Init new buffer settings.
+ //
+ m_pDataBuffer = buffer;
+ m_ulBufferSize = bufferSize;
+ m_ulFrameSize = ulMaxWriteSize;
+
+ ntStatus = STATUS_SUCCESS;
+
+Done:
+ return ntStatus;
+} // SetDataFormat
+
+//=============================================================================
+void
+CSaveData::ReadData
+(
+ _Inout_updates_bytes_all_(ulByteCount) PBYTE pBuffer,
+ _In_ ULONG ulByteCount
+)
+{
+ UNREFERENCED_PARAMETER(pBuffer);
+ UNREFERENCED_PARAMETER(ulByteCount);
+
+ PAGED_CODE();
+
+ // Not implemented yet.
+} // ReadData
+
+//=============================================================================
+#pragma code_seg()
+void
+CSaveData::SaveFrame
+(
+ _In_ ULONG ulFrameNo,
+ _In_ ULONG ulDataSize
+)
+{
+ PSAVEWORKER_PARAM pParam = NULL;
+
+ DPF_ENTER(("[CSaveData::SaveFrame]"));
+
+ pParam = GetNewWorkItem();
+ if (pParam)
+ {
+ pParam->pSaveData = this;
+ pParam->ulFrameNo = ulFrameNo;
+ pParam->ulDataSize = ulDataSize;
+ pParam->pData = m_pDataBuffer + ulFrameNo * m_ulFrameSize;
+ KeResetEvent(&pParam->EventDone);
+ IoQueueWorkItem(pParam->WorkItem, SaveFrameWorkerCallback,
+ CriticalWorkQueue, (PVOID)pParam);
+ }
+} // SaveFrame
+#pragma code_seg("PAGE")
+//=============================================================================
+void
+CSaveData::WaitAllWorkItems
+(
+ void
+)
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CSaveData::WaitAllWorkItems]"));
+
+ // Save the last partially-filled frame
+ if (m_ulBufferOffset > m_ulFrameIndex * m_ulFrameSize)
+ {
+ ULONG size;
+
+ size = m_ulBufferOffset - m_ulFrameIndex * m_ulFrameSize;
+ SaveFrame(m_ulFrameIndex, size);
+ }
+
+ for (int i = 0; i < MAX_WORKER_ITEM_COUNT; i++)
+ {
+ DPF(D_VERBOSE, ("[Waiting for WorkItem] %d", i));
+ KeWaitForSingleObject
+ (
+ &(m_pWorkItems[i].EventDone),
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+ }
+} // WaitAllWorkItems
+
+#pragma code_seg()
+//=============================================================================
+void
+CSaveData::WriteData
+(
+ _In_reads_bytes_(ulByteCount) PBYTE pBuffer,
+ _In_ ULONG ulByteCount
+)
+{
+ ASSERT(pBuffer);
+
+ BOOL fSaveFrame = FALSE;
+ ULONG ulSaveFrameIndex = 0;
+ KIRQL oldIrql;
+
+ // If stream writing is disabled, then exit.
+ //
+ if (m_fWriteDisabled)
+ {
+ return;
+ }
+
+ DPF_ENTER(("[CSaveData::WriteData ulByteCount=%lu]", ulByteCount));
+
+ if( 0 == ulByteCount )
+ {
+ return;
+ }
+
+ // The logic below assumes that write size is <= than frame size.
+ if (ulByteCount > m_ulFrameSize)
+ {
+ ulByteCount = m_ulFrameSize;
+ }
+
+ // Check to see if this frame is available.
+ KeAcquireSpinLock(&m_FrameInUseSpinLock, &oldIrql);
+ if (!m_fFrameUsed[m_ulFrameIndex])
+ {
+ KeReleaseSpinLock(&m_FrameInUseSpinLock, oldIrql );
+
+ ULONG ulWriteBytes = ulByteCount;
+
+ if( (m_ulBufferSize - m_ulBufferOffset) < ulWriteBytes )
+ {
+ ulWriteBytes = m_ulBufferSize - m_ulBufferOffset;
+ }
+
+ RtlCopyMemory(m_pDataBuffer + m_ulBufferOffset, pBuffer, ulWriteBytes);
+ m_ulBufferOffset += ulWriteBytes;
+
+ // Check to see if we need to save this frame
+ if (m_ulBufferOffset >= ((m_ulFrameIndex + 1) * m_ulFrameSize))
+ {
+ fSaveFrame = TRUE;
+ }
+
+ // Loop the buffer, if we reached the end.
+ if (m_ulBufferOffset == m_ulBufferSize)
+ {
+ fSaveFrame = TRUE;
+ m_ulBufferOffset = 0;
+ }
+
+ if (fSaveFrame)
+ {
+ InterlockedExchange( (LONG *)&(m_fFrameUsed[m_ulFrameIndex]), TRUE );
+ ulSaveFrameIndex = m_ulFrameIndex;
+ m_ulFrameIndex = (m_ulFrameIndex + 1) % m_ulFrameCount;
+ }
+
+ // Write the left over if the next frame is available.
+ if (ulWriteBytes != ulByteCount)
+ {
+ KeAcquireSpinLock(&m_FrameInUseSpinLock, &oldIrql );
+ if (!m_fFrameUsed[m_ulFrameIndex])
+ {
+ KeReleaseSpinLock(&m_FrameInUseSpinLock, oldIrql );
+ RtlCopyMemory
+ (
+ m_pDataBuffer + m_ulBufferOffset,
+ pBuffer + ulWriteBytes,
+ ulByteCount - ulWriteBytes
+ );
+
+ m_ulBufferOffset += ulByteCount - ulWriteBytes;
+ }
+ else
+ {
+ KeReleaseSpinLock(&m_FrameInUseSpinLock, oldIrql);
+ DPF(D_BLAB, ("[Frame overflow, next frame is in use]"));
+ }
+ }
+
+ if (fSaveFrame)
+ {
+ SaveFrame(ulSaveFrameIndex, m_ulFrameSize);
+ }
+ }
+ else
+ {
+ KeReleaseSpinLock(&m_FrameInUseSpinLock, oldIrql );
+ DPF(D_BLAB, ("[Frame %d is in use]", m_ulFrameIndex));
+ }
+
+} // WriteData
+
diff --git a/audio/simpleaudiosample/Source/Utilities/savedata.h b/audio/simpleaudiosample/Source/Utilities/savedata.h
new file mode 100644
index 00000000..c658ec71
--- /dev/null
+++ b/audio/simpleaudiosample/Source/Utilities/savedata.h
@@ -0,0 +1,189 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ savedata.h
+
+Abstract:
+
+ Declaration of Simple Audio Sample data saving class. This class supplies services
+to save data to disk.
+
+--*/
+
+#ifndef _SIMPLEAUDIOSAMPLE_SAVEDATA_H
+#define _SIMPLEAUDIOSAMPLE_SAVEDATA_H
+
+//-----------------------------------------------------------------------------
+// Forward declaration
+//-----------------------------------------------------------------------------
+class CSaveData;
+typedef CSaveData *PCSaveData;
+
+
+//-----------------------------------------------------------------------------
+// Structs
+//-----------------------------------------------------------------------------
+
+// Parameter to workitem.
+#include <pshpack1.h>
+typedef struct _SAVEWORKER_PARAM {
+ PIO_WORKITEM WorkItem;
+ ULONG ulFrameNo;
+ ULONG ulDataSize;
+ PBYTE pData;
+ PCSaveData pSaveData;
+ KEVENT EventDone;
+} SAVEWORKER_PARAM;
+typedef SAVEWORKER_PARAM *PSAVEWORKER_PARAM;
+#include <poppack.h>
+
+// wave file header.
+#include <pshpack1.h>
+typedef struct _OUTPUT_FILE_HEADER
+{
+ DWORD dwRiff;
+ DWORD dwFileSize;
+ DWORD dwWave;
+ DWORD dwFormat;
+ DWORD dwFormatLength;
+} OUTPUT_FILE_HEADER;
+typedef OUTPUT_FILE_HEADER *POUTPUT_FILE_HEADER;
+
+typedef struct _OUTPUT_DATA_HEADER
+{
+ DWORD dwData;
+ DWORD dwDataLength;
+} OUTPUT_DATA_HEADER;
+typedef OUTPUT_DATA_HEADER *POUTPUT_DATA_HEADER;
+
+#include <poppack.h>
+
+//-----------------------------------------------------------------------------
+// Classes
+//-----------------------------------------------------------------------------
+
+///////////////////////////////////////////////////////////////////////////////
+// CSaveData
+// Saves the wave data to disk.
+//
+IO_WORKITEM_ROUTINE SaveFrameWorkerCallback;
+
+class CSaveData
+{
+protected:
+ UNICODE_STRING m_FileName; // DataFile name.
+ HANDLE m_FileHandle; // DataFile handle.
+ PBYTE m_pDataBuffer; // Data buffer.
+ ULONG m_ulBufferSize; // Total buffer size.
+
+ ULONG m_ulFrameIndex; // Current Frame.
+ ULONG m_ulFrameCount; // Frame count.
+ ULONG m_ulFrameSize;
+ ULONG m_ulBufferOffset; // index in buffer.
+ PBOOL m_fFrameUsed; // Frame usage table.
+ KSPIN_LOCK m_FrameInUseSpinLock; // Spinlock for synch.
+ KMUTEX m_FileSync; // Synchronizes file access
+
+ OBJECT_ATTRIBUTES m_objectAttributes; // Used for opening file.
+
+ OUTPUT_FILE_HEADER m_FileHeader;
+ PWAVEFORMATEX m_waveFormat;
+ OUTPUT_DATA_HEADER m_DataHeader;
+ PLARGE_INTEGER m_pFilePtr;
+
+ static PDEVICE_OBJECT m_pDeviceObject;
+ static ULONG m_ulStreamId;
+ static PSAVEWORKER_PARAM m_pWorkItems;
+
+ BOOL m_fWriteDisabled;
+
+ BOOL m_bInitialized;
+
+public:
+ CSaveData();
+ ~CSaveData();
+
+ static NTSTATUS InitializeWorkItems
+ (
+ _In_ PDEVICE_OBJECT DeviceObject
+ );
+ static void DestroyWorkItems
+ (
+ void
+ );
+ void Disable
+ (
+ _In_ BOOL fDisable
+ );
+ static PSAVEWORKER_PARAM GetNewWorkItem
+ (
+ void
+ );
+ NTSTATUS Initialize
+ (
+ );
+ static NTSTATUS SetDeviceObject
+ (
+ _In_ PDEVICE_OBJECT DeviceObject
+ );
+ static PDEVICE_OBJECT GetDeviceObject
+ (
+ void
+ );
+ void ReadData
+ (
+ _Inout_updates_bytes_all_(ulByteCount) PBYTE pBuffer,
+ _In_ ULONG ulByteCount
+ );
+ NTSTATUS SetDataFormat
+ (
+ _In_ PKSDATAFORMAT pDataFormat
+ );
+ NTSTATUS SetMaxWriteSize
+ (
+ _In_ ULONG ulMaxWriteSize
+ );
+ void WaitAllWorkItems
+ (
+ void
+ );
+ void WriteData
+ (
+ _In_reads_bytes_(ulByteCount) PBYTE pBuffer,
+ _In_ ULONG ulByteCount
+ );
+
+private:
+ NTSTATUS FileClose
+ (
+ void
+ );
+ NTSTATUS FileOpen
+ (
+ _In_ BOOL fOverWrite
+ );
+ NTSTATUS FileWrite
+ (
+ _In_reads_bytes_(ulDataSize) PBYTE pData,
+ _In_ ULONG ulDataSize
+ );
+ NTSTATUS FileWriteHeader
+ (
+ void
+ );
+
+ void SaveFrame
+ (
+ _In_ ULONG ulFrameNo,
+ _In_ ULONG ulDataSize
+ );
+
+ friend
+ IO_WORKITEM_ROUTINE SaveFrameWorkerCallback;
+};
+typedef CSaveData *PCSaveData;
+
+#endif
diff --git a/audio/sysvad/EndpointsCommon/EndpointsCommon.vcxproj b/audio/sysvad/EndpointsCommon/EndpointsCommon.vcxproj
index b4d1c802..6a7a4678 100644
--- a/audio/sysvad/EndpointsCommon/EndpointsCommon.vcxproj
+++ b/audio/sysvad/EndpointsCommon/EndpointsCommon.vcxproj
@@ -140,6 +140,9 @@
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND</PreprocessorDefinitions>
</Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<ResourceCompile>
@@ -157,6 +160,9 @@
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND</PreprocessorDefinitions>
</Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ResourceCompile>
@@ -174,6 +180,9 @@
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND</PreprocessorDefinitions>
</Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<ResourceCompile>
@@ -191,6 +200,9 @@
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND</PreprocessorDefinitions>
</Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ResourceCompile>
@@ -208,6 +220,9 @@
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND</PreprocessorDefinitions>
</Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ResourceCompile>
@@ -225,6 +240,9 @@
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND</PreprocessorDefinitions>
</Midl>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="AudioModuleHelper.cpp" />
diff --git a/audio/sysvad/EndpointsCommon/mintopo.cpp b/audio/sysvad/EndpointsCommon/mintopo.cpp
index 28ddf419..4e417c4a 100644
--- a/audio/sysvad/EndpointsCommon/mintopo.cpp
+++ b/audio/sysvad/EndpointsCommon/mintopo.cpp
@@ -570,7 +570,7 @@ Return Value:
// 0x00000002 - JACKDESC2_DYNAMIC_FORMAT_CHANGE_CAPABILITY
//
pDesc->JackCapabilities = JackCapabilities;
-
+
ntStatus = STATUS_SUCCESS;
}
}
@@ -581,6 +581,7 @@ Return Value:
return ntStatus;
}
+
#if defined(SYSVAD_BTH_BYPASS) || defined(SYSVAD_USB_SIDEBAND)
//=============================================================================
#pragma code_seg()
diff --git a/audio/sysvad/EndpointsCommon/mintopo.h b/audio/sysvad/EndpointsCommon/mintopo.h
index 4aa3d2de..b4eda617 100644
--- a/audio/sysvad/EndpointsCommon/mintopo.h
+++ b/audio/sysvad/EndpointsCommon/mintopo.h
@@ -33,6 +33,8 @@ class CMiniportTopology :
{
private:
eDeviceType m_DeviceType;
+
+
union {
PVOID m_DeviceContext;
#if defined(SYSVAD_BTH_BYPASS) || defined(SYSVAD_USB_SIDEBAND)
@@ -55,6 +57,7 @@ public:
m_DeviceType(DeviceType),
m_DeviceContext(DeviceContext)
{
+
#if defined(SYSVAD_BTH_BYPASS) || defined(SYSVAD_USB_SIDEBAND)
if (IsSidebandDevice())
{
@@ -73,18 +76,19 @@ public:
NTSTATUS PropertyHandlerJackDescription
(
- _In_ PPCPROPERTY_REQUEST PropertyRequest,
- _In_ ULONG cJackDescriptions,
- _In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION * JackDescriptions
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG cJackDescriptions,
+ _In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION *JackDescriptions
);
NTSTATUS PropertyHandlerJackDescription2
(
- _In_ PPCPROPERTY_REQUEST PropertyRequest,
- _In_ ULONG cJackDescriptions,
- _In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION * JackDescriptions,
- _In_ DWORD JackCapabilities
+ _In_ PPCPROPERTY_REQUEST PropertyRequest,
+ _In_ ULONG cJackDescriptions,
+ _In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION *JackDescriptions,
+ _In_ DWORD JackCapabilities
);
+
#if defined(SYSVAD_BTH_BYPASS) || defined(SYSVAD_USB_SIDEBAND)
BOOL IsSidebandDevice()
diff --git a/audio/sysvad/EndpointsCommon/minwavertstream.cpp b/audio/sysvad/EndpointsCommon/minwavertstream.cpp
index 93ecdcf3..499d5b38 100644
--- a/audio/sysvad/EndpointsCommon/minwavertstream.cpp
+++ b/audio/sysvad/EndpointsCommon/minwavertstream.cpp
@@ -968,12 +968,12 @@ NTSTATUS CMiniportWaveRTStream::GetReadPacket
// Return next packet number to be read
*PacketNumber = availablePacketNumber;
- // Compute and return timestamp corresponding to start of the available packet. In a real hardware
+ // Compute and return timestamp corresponding to the end of the available packet. In a real hardware
// driver, the timestamp would be computed in a driver and hardware specific manner. In this sample
// driver, it is extrapolated from the sample driver's internal simulated position correlation
// [m_ullLinearPosition @ m_ullDmaTimeStamp] and the sample's internal 64-bit packet counter, subtracting
// 1 from the packet counter to compute the time at the start of that last completed packet.
- ULONGLONG linearPositionOfAvailablePacket = (packetCounter - 1) * (m_ulDmaBufferSize / m_ulNotificationsPerBuffer);
+ ULONGLONG linearPositionOfAvailablePacket = packetCounter * (m_ulDmaBufferSize / m_ulNotificationsPerBuffer);
// Need to divide by (1000 * 10000 because m_ulDmaMovementRate is average bytes per sec
ULONGLONG carryForwardBytes = (hnsElapsedTimeCarryForward * m_ulDmaMovementRate) / 10000000;
ULONGLONG deltaLinearPosition = ullLinearPosition + carryForwardBytes - linearPositionOfAvailablePacket;
diff --git a/audio/sysvad/EndpointsCommon/speakertopo.cpp b/audio/sysvad/EndpointsCommon/speakertopo.cpp
index cca4dac9..fee3d542 100644
--- a/audio/sysvad/EndpointsCommon/speakertopo.cpp
+++ b/audio/sysvad/EndpointsCommon/speakertopo.cpp
@@ -22,7 +22,6 @@ Abstract:
#pragma code_seg("PAGE")
-
//=============================================================================
NTSTATUS
PropertyHandler_SpeakerTopoFilter
diff --git a/audio/sysvad/EndpointsCommon/speakertoptable.h b/audio/sysvad/EndpointsCommon/speakertoptable.h
index 50f58c7b..6850c0cf 100644
--- a/audio/sysvad/EndpointsCommon/speakertoptable.h
+++ b/audio/sysvad/EndpointsCommon/speakertoptable.h
@@ -85,7 +85,7 @@ PCPIN_DESCRIPTOR SpeakerTopoMiniportPins[] =
//=============================================================================
static
-KSJACK_DESCRIPTION SpeakerJackDescSpeakers =
+KSJACK_DESCRIPTION SpeakerJackDescBridge =
{
KSAUDIO_SPEAKER_STEREO,
0xB3C98C, // Color spec for green
@@ -101,9 +101,10 @@ static
PKSJACK_DESCRIPTION SpeakerJackDescriptions[] =
{
NULL,
- &SpeakerJackDescSpeakers
+ &SpeakerJackDescBridge
};
+
//=============================================================================
static
PCCONNECTION_DESCRIPTOR SpeakerTopoMiniportConnections[] =
@@ -120,13 +121,15 @@ PCPROPERTY_ITEM PropertiesSpeakerTopoFilter[] =
{
&KSPROPSETID_Jack,
KSPROPERTY_JACK_DESCRIPTION,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
+ KSPROPERTY_TYPE_GET |
+ KSPROPERTY_TYPE_BASICSUPPORT,
PropertyHandler_SpeakerTopoFilter
},
{
&KSPROPSETID_Jack,
KSPROPERTY_JACK_DESCRIPTION2,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
+ KSPROPERTY_TYPE_GET |
+ KSPROPERTY_TYPE_BASICSUPPORT,
PropertyHandler_SpeakerTopoFilter
}
};
@@ -152,4 +155,4 @@ PCFILTER_DESCRIPTOR SpeakerTopoMiniportFilterDescriptor =
};
#endif // _SYSVAD_SPEAKERTOPTABLE_H_
-
+
diff --git a/audio/sysvad/Package/package.VcxProj b/audio/sysvad/Package/package.VcxProj
index dba6d6b4..aedc7dc4 100644
--- a/audio/sysvad/Package/package.VcxProj
+++ b/audio/sysvad/Package/package.VcxProj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM64">
@@ -30,9 +30,6 @@
<ProjectReference Include="..\KeywordDetectorAdapter\KeywordDetectorContosoAdapter.vcxproj">
<Project>{E0F02048-78A4-4FE8-B863-66E6CB6A2C37}</Project>
</ProjectReference>
- <ProjectReference Include="..\PhoneAudioSample\PhoneAudioSample.vcxproj">
- <Project>{FABA4668-DB5E-4F6C-9D25-A0B25AD084EE}</Project>
- </ProjectReference>
<ProjectReference Include="..\APO\SwapAPO\SwapAPO.vcxproj">
<Project>{691F1D0F-CA50-46CD-8BBA-A59E9E8EB601}</Project>
</ProjectReference>
@@ -107,9 +104,37 @@
<VerifyDrivers />
<VerifyFlags>133563</VerifyFlags>
</PropertyGroup>
- <ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project> \ No newline at end of file
+</Project>
diff --git a/audio/sysvad/PhoneAudioSample/CellularWave.cpp b/audio/sysvad/PhoneAudioSample/CellularWave.cpp
deleted file mode 100644
index 1a999c1e..00000000
--- a/audio/sysvad/PhoneAudioSample/CellularWave.cpp
+++ /dev/null
@@ -1,685 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- cellularwave.cpp
-
-Abstract:
-
- Implementation of wavert miniport for cellular
-
---*/
-
-#pragma warning (disable : 4127)
-
-#include <sysvad.h>
-#include "simple.h"
-#include "CellularWave.h"
-#include "CellularTopo.h"
-#include "CellularToptable.h"
-
-//=============================================================================
-// CCellularMiniportWaveRT
-//=============================================================================
-
-//=============================================================================
-#pragma code_seg("PAGE")
-NTSTATUS
-CreateCellularMiniportWaveRT
-(
- _Out_ PUNKNOWN * Unknown,
- _In_ REFCLSID,
- _In_opt_ PUNKNOWN UnknownOuter,
- _When_((PoolType & NonPagedPoolMustSucceed) != 0,
- __drv_reportError("Must succeed pool allocations are forbidden. "
- "Allocation failures cause a system crash"))
- _In_ POOL_TYPE PoolType,
- _In_ PUNKNOWN UnknownAdapter,
- _In_opt_ PVOID DeviceContext,
- _In_ PENDPOINT_MINIPAIR MiniportPair
-)
-/*++
-
-Routine Description:
-
- Create the wavert miniport.
-
-Arguments:
-
- Unknown -
-
- RefClsId -
-
- UnknownOuter -
-
- PoolType -
-
- UnkownAdapter -
-
- DeviceContext -
-
- MiniportPair -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- UNREFERENCED_PARAMETER(UnknownOuter);
-
- PAGED_CODE();
-
- ASSERT(Unknown);
- ASSERT(MiniportPair);
-
- CMiniportWaveRT *obj = new (PoolType, MINWAVERT_POOLTAG) CCellularMiniportWaveRT
- (
- UnknownAdapter,
- MiniportPair,
- DeviceContext
- );
- if (NULL == obj)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- obj->AddRef();
- *Unknown = reinterpret_cast<IUnknown*>(obj);
-
- return STATUS_SUCCESS;
-}
-
-//=============================================================================
-#pragma code_seg("PAGE")
-CCellularMiniportWaveRT::~CCellularMiniportWaveRT
-(
- void
-)
-/*++
-
-Routine Description:
-
- Destructor for wavert miniport
-
-Arguments:
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- DPF_ENTER(("[CCellularMiniportWaveRT::~CCellularMiniportWaveRT]"));
-
-} // ~CCellularMiniportWaveRT
-
-
-//=============================================================================
-#pragma code_seg("PAGE")
-STDMETHODIMP
-CCellularMiniportWaveRT::NonDelegatingQueryInterface
-(
- _In_ REFIID Interface,
- _COM_Outptr_ PVOID * Object
-)
-/*++
-
-Routine Description:
-
- QueryInterface for CCellularMiniportWaveRT
-
-Arguments:
-
- Interface - GUID of the interface
-
- Object - interface object to be returned.
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(Object);
-
- if (IsEqualGUIDAligned(Interface, IID_IAdapterPowerManagement))
- {
- *Object = PVOID(PADAPTERPOWERMANAGEMENT(this));
- }
- else
- {
- *Object = NULL;
- }
-
- if (*Object)
- {
- // We reference the interface for the caller.
-
- PUNKNOWN(*Object)->AddRef();
- return STATUS_SUCCESS;
- }
-
- return CMiniportWaveRT::NonDelegatingQueryInterface(Interface, Object);
-}
-
-#pragma code_seg("PAGE")
-NTSTATUS
-PropertyHandler_CellularWaveFilter
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Redirects general property request to miniport object
-
-Arguments:
-
- PropertyRequest -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- CCellularMiniportWaveRT* pWaveHelper = reinterpret_cast<CCellularMiniportWaveRT*>(PropertyRequest->MajorTarget);
-
- if (pWaveHelper == NULL)
- {
- return STATUS_INVALID_PARAMETER;
- }
-
- pWaveHelper->AddRef();
-
- if (pWaveHelper->m_DeviceType == eCellularDevice &&
- IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_TelephonyControl))
- {
- switch (PropertyRequest->PropertyItem->Id)
- {
- case KSPROPERTY_TELEPHONY_PROVIDERID:
- ntStatus = pWaveHelper->PropertyHandler_TelephonyProviderId(PropertyRequest);
- break;
-
- case KSPROPERTY_TELEPHONY_CALLINFO:
- ntStatus = pWaveHelper->PropertyHandler_TelephonyCallInfo(PropertyRequest);
- break;
-
- case KSPROPERTY_TELEPHONY_CALLCONTROL:
- case KSPROPERTY_TELEPHONY_PROVIDERCHANGE:
- ntStatus = pWaveHelper->PropertyHandler_TelephonyCallState(PropertyRequest);
- break;
-
- case KSPROPERTY_TELEPHONY_CALLHOLD:
- ntStatus = pWaveHelper->PropertyHandler_TelephonyCallHold(PropertyRequest);
- break;
-
- case KSPROPERTY_TELEPHONY_MUTE_TX:
- ntStatus = pWaveHelper->PropertyHandler_TelephonyMuteTx(PropertyRequest);
- break;
-
- default:
- DPF(D_TERSE, ("[PropertyHandler_CellularWaveFilter: Invalid Device Request]"));
- }
- }
- else
- {
- ntStatus = PropertyHandler_WaveFilter(PropertyRequest);
- }
-
- pWaveHelper->Release();
-
- return ntStatus;
-} // PropertyHandler_CellularWaveFilter
-
-//=============================================================================
-#pragma code_seg("PAGE")
-NTSTATUS
-CCellularMiniportWaveRT::PropertyHandler_TelephonyProviderId
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-{
- NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
-
- PAGED_CODE();
-
- DPF_ENTER(("[CCellularMiniportWaveRT::PropertyHandler_TelephonyProviderId]"));
-
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ULONG flags = PropertyRequest->PropertyItem->Flags;
- ntStatus = PropertyHandler_BasicSupport(PropertyRequest, flags, VT_ILLEGAL);
- }
- else
- {
- ULONG cbMinSize = sizeof(ULONG);
-
- if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = cbMinSize;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else if (PropertyRequest->ValueSize < cbMinSize)
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- ULONG* providerId = (ULONG*)PropertyRequest->Value;
- // Return supported TelephonyProviderId (executor id).
- *providerId = m_TelephonyProviderId;
- ntStatus = STATUS_SUCCESS;
- }
- else
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- }
-
- return ntStatus;
-} // PropertyHandler_TelephonyProviderId
-
-//=============================================================================
-#pragma code_seg("PAGE")
-NTSTATUS
-CCellularMiniportWaveRT::PropertyHandler_TelephonyCallInfo
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-{
- NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
-
- PAGED_CODE();
-
- DPF_ENTER(("[CCellularMiniportWaveRT::PropertyHandler_TelephonyCallInfo]"));
-
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ULONG flags = PropertyRequest->PropertyItem->Flags;
- ntStatus = PropertyHandler_BasicSupport(PropertyRequest, flags, VT_ILLEGAL);
- }
- else
- {
- ULONG cbMinSize = sizeof(KSTELEPHONY_CALLINFO);
-
- if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = cbMinSize;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else if (PropertyRequest->ValueSize < cbMinSize)
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- PKSTELEPHONY_CALLINFO TelephonyCallInfo = static_cast<PKSTELEPHONY_CALLINFO>(PropertyRequest->Value);
- // Return current CallType and CallState information. CallType information is not valid when the CallState is disabled.
- TelephonyCallInfo->CallType = m_TelephonyCallType;
- TelephonyCallInfo->CallState = m_TelephonyCallState;
- ntStatus = STATUS_SUCCESS;
- }
- else
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- }
-
- return ntStatus;
-} // PropertyHandler_TelephonyCallInfo
-
-#pragma code_seg("PAGE")
-NTSTATUS
-CCellularMiniportWaveRT::UpdateTopologyJackState
-(
- _In_ ULONG TelephonyId,
- _In_ BOOL NewState
-)
-{
- PAGED_CODE ();
- NTSTATUS ntStatus = STATUS_SUCCESS;
- IUnknown *pUnknown = NULL;
- ICellularTopology *pCellularTopology = NULL;
-
- // GetFilters returns the topology port, then topology miniport, then wave port, then wave miniport.
- // we only need the topology miniport.
- ntStatus = m_pAdapterCommon->GetFilters(m_pMiniportPair, NULL, &pUnknown, NULL, NULL);
- if (NT_SUCCESS(ntStatus))
- {
- ntStatus = pUnknown->QueryInterface(IID_ICellularTopology, (PVOID *)&pCellularTopology);
- if (NT_SUCCESS(ntStatus))
- {
- ntStatus = pCellularTopology->UpdateTopologyJackState(TelephonyId, NewState);
- }
- }
-
- SAFE_RELEASE(pCellularTopology);
- SAFE_RELEASE(pUnknown);
-
- return STATUS_SUCCESS;
-}
-#pragma code_seg()
-
-//=============================================================================
-#pragma code_seg("PAGE")
-NTSTATUS
-CCellularMiniportWaveRT::PropertyHandler_TelephonyCallState
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-{
- NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
-
- PAGED_CODE();
-
- DPF_ENTER(("[CCellularMiniportWaveRT::PropertyHandler_TelephonyCallState]"));
-
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ULONG flags = PropertyRequest->PropertyItem->Flags;
- ntStatus = PropertyHandler_BasicSupport(PropertyRequest, flags, VT_ILLEGAL);
- }
- else
- {
- ULONG cbMinSize = 0;
-
- if (PropertyRequest->PropertyItem->Id == KSPROPERTY_TELEPHONY_CALLCONTROL)
- {
- cbMinSize = sizeof(KSTELEPHONY_CALLCONTROL);
- }
- else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_TELEPHONY_PROVIDERCHANGE)
- {
- cbMinSize = sizeof(KSTELEPHONY_PROVIDERCHANGE);
- }
-
- if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = cbMinSize;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else if (PropertyRequest->ValueSize < cbMinSize)
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
- {
- if (PropertyRequest->PropertyItem->Id == KSPROPERTY_TELEPHONY_CALLCONTROL)
- {
- PKSTELEPHONY_CALLCONTROL TelephonyCallControl = static_cast<PKSTELEPHONY_CALLCONTROL>(PropertyRequest->Value);
-
- // KSPROPERTY_TELEPHONY_CALLCONTROL has info about CallType and CallControlOp. TELEPHONY_CALLCONTROLOP_ENABLE will start
- // cellular call from audio driver perspective, update jack state for associated cellular bidi endpoint to active,
- // save call type and update the call state to Enabled. TELEPHONY_CALLCONTROLOP_DISABLE will terminate cellular call
- // from audio driver perspective, update jack state for associated cellular bidi endpoint to unplugged and update
- // call state to Disabled. Call type is ignored in this case.
- switch (TelephonyCallControl->CallControlOp)
- {
- case TELEPHONY_CALLCONTROLOP_DISABLE:
- ASSERT(m_TelephonyCallState != TELEPHONY_CALLSTATE_DISABLED);
- m_TelephonyCallState = TELEPHONY_CALLSTATE_DISABLED;
- UpdateTopologyJackState(m_TelephonyProviderId, FALSE);
- // Release our idle power management requirement
- m_pAdapterCommon->SetIdlePowerManagement(m_pMiniportPair, TRUE);
- ntStatus = STATUS_SUCCESS;
- break;
-
- case TELEPHONY_CALLCONTROLOP_ENABLE:
- ASSERT(m_TelephonyCallState != TELEPHONY_CALLSTATE_ENABLED);
- m_TelephonyCallType = TelephonyCallControl->CallType;
- m_TelephonyCallState = TELEPHONY_CALLSTATE_ENABLED;
- UpdateTopologyJackState(m_TelephonyProviderId, TRUE);
- // When we're in a call, we need idle power management disabled.
- m_pAdapterCommon->SetIdlePowerManagement(m_pMiniportPair, FALSE);
- ntStatus = STATUS_SUCCESS;
- break;
-
- default:
- ntStatus = STATUS_INVALID_PARAMETER;
- break;
- }
- }
- else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_TELEPHONY_PROVIDERCHANGE)
- {
- PKSTELEPHONY_PROVIDERCHANGE TelephonyProviderChange = static_cast<PKSTELEPHONY_PROVIDERCHANGE>(PropertyRequest->Value);
-
- // KSPROPERTY_TELEPHONY_PROVIDERCHANGE has info about CallType and ProviderChangeOp. TELEPHONY_PROVIDERCHANGEOP_BEGIN will indicate
- // start of SRVCC to audio driver. Audio driver will then start the SRVCC and update the call state to ProviderTransition.
- // TELEPHONY_PROVIDERCHANGEOP_END will indicate end of SRVCC to audio driver and driver will end SRVCC process and update
- // call state to Enabled. TELEPHONY_PROVIDERCHANGEOP_CANCEL will indicate SRVCC was aborted and audio driver will revert back to
- // pre SRVCC call.
- switch (TelephonyProviderChange->ProviderChangeOp)
- {
- case TELEPHONY_PROVIDERCHANGEOP_END:
- m_TelephonyCallState = TELEPHONY_CALLSTATE_ENABLED;
- ntStatus = STATUS_SUCCESS;
- break;
-
- case TELEPHONY_PROVIDERCHANGEOP_BEGIN:
- m_PreviousTelephonyCallType = m_TelephonyCallType;
- m_TelephonyCallType = TelephonyProviderChange->CallType;
- m_TelephonyCallState = TELEPHONY_CALLSTATE_PROVIDERTRANSITION;
- ntStatus = STATUS_SUCCESS;
- break;
-
- case TELEPHONY_PROVIDERCHANGEOP_CANCEL:
- m_TelephonyCallType = m_PreviousTelephonyCallType;
- m_TelephonyCallState = TELEPHONY_CALLSTATE_ENABLED;
- ntStatus = STATUS_SUCCESS;
- break;
-
- default:
- ntStatus = STATUS_INVALID_PARAMETER;
- break;
- }
- }
- else
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- else
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- }
-
- return ntStatus;
-} // PropertyHandler_TelephonyCallState
-
-//=============================================================================
-#pragma code_seg("PAGE")
-NTSTATUS
-CCellularMiniportWaveRT::PropertyHandler_TelephonyCallHold
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-{
- NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
-
- PAGED_CODE();
-
- DPF_ENTER(("[CCellularMiniportWaveRT::PropertyHandler_TelephonyCallHold]"));
-
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ULONG flags = PropertyRequest->PropertyItem->Flags;
- ntStatus = PropertyHandler_BasicSupport(PropertyRequest, flags, VT_ILLEGAL);
- }
- else
- {
- ULONG cbMinSize = sizeof(BOOL);
-
- if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = cbMinSize;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else if (PropertyRequest->ValueSize < cbMinSize)
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- BOOL* bTelephonyHold = (BOOL*) PropertyRequest->Value;
- // Return if the call is on hold or not
- *bTelephonyHold = m_bTelephonyHold;
- ntStatus = STATUS_SUCCESS;
- }
- else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
- {
- BOOL* bTelephonyHold = (BOOL*) PropertyRequest->Value;
- m_bTelephonyHold = *bTelephonyHold;
-
- // If this property is TRUE, put the call on hold and update the call state to hold.
- // If this property is FALSE, take the call out of hold and update the call state to enabled.
- m_TelephonyCallState = (*bTelephonyHold) ? TELEPHONY_CALLSTATE_HOLD : TELEPHONY_CALLSTATE_ENABLED;
- ntStatus = STATUS_SUCCESS;
- }
- else
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- }
-
- return ntStatus;
-} // PropertyHandler_TelephonyCallHold
-
-//=============================================================================
-#pragma code_seg("PAGE")
-NTSTATUS
-CCellularMiniportWaveRT::PropertyHandler_TelephonyMuteTx
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-{
- NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
-
- PAGED_CODE();
-
- DPF_ENTER(("[CCellularMiniportWaveRT::PropertyHandler_TelephonyMuteTx]"));
-
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ULONG flags = PropertyRequest->PropertyItem->Flags;
- ntStatus = PropertyHandler_BasicSupport(PropertyRequest, flags, VT_ILLEGAL);
- }
- else
- {
- ULONG cbMinSize = sizeof(BOOL);
-
- if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = cbMinSize;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else if (PropertyRequest->ValueSize < cbMinSize)
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- BOOL* bTxMute = (BOOL*) PropertyRequest->Value;
- // Return if the cellular Tx is on muted or not
- *bTxMute = m_bTelephonyMuteTx;
- ntStatus = STATUS_SUCCESS;
- }
- else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
- {
- BOOL* bTxMute = (BOOL*) PropertyRequest->Value;
- // If this property is TRUE, mute cellular Tx data. However, it should not mute the data that was injected to KSNODETYPE_TELEPHONY_TX.
- // If this property is FALSE, unmute cellular Tx data.
- m_bTelephonyMuteTx = *bTxMute;
- ntStatus = STATUS_SUCCESS;
- }
- else
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- }
-
- return ntStatus;
-} // PropertyHandler_TelephonyMuteTx
-
-//=============================================================================
-#pragma code_seg()
-STDMETHODIMP_(void)
-CCellularMiniportWaveRT::PowerChangeState
-(
- _In_ POWER_STATE NewState
-)
-{
- DPF_ENTER(("[CCellularMiniportWaveRT::PowerChangeState]"));
- UNREFERENCED_PARAMETER(NewState);
-
- /*
- Turn on and off cellular specific hardware here, if applicable.
- */
-
-} // PowerStateChange
-
-//=============================================================================
-#pragma code_seg()
-STDMETHODIMP_(NTSTATUS)
-CCellularMiniportWaveRT::QueryDeviceCapabilities
-(
- _Inout_updates_bytes_(sizeof(DEVICE_CAPABILITIES)) PDEVICE_CAPABILITIES PowerDeviceCaps
-)
-{
- UNREFERENCED_PARAMETER(PowerDeviceCaps);
-
- /*
- Unused at the miniport layer. Any device capabilities should be reported in CAdapterCommon
- */
-
- return (STATUS_SUCCESS);
-} // QueryDeviceCapabilities
-
-//=============================================================================
-#pragma code_seg()
-STDMETHODIMP_(NTSTATUS)
-CCellularMiniportWaveRT::QueryPowerChangeState
-(
- _In_ POWER_STATE NewStateQuery
-)
-{
- UNREFERENCED_PARAMETER(NewStateQuery);
-
- DPF_ENTER(("[CCellularMiniportWaveRT::QueryPowerChangeState]"));
-
- // if we're in a call state other than disabled, then we need the hardware turned on.
- if (TELEPHONY_CALLSTATE_DISABLED != m_TelephonyCallState)
- {
- return STATUS_RESOURCE_IN_USE;
- }
-
- return STATUS_SUCCESS;
-} // QueryPowerChangeState
-
-
diff --git a/audio/sysvad/PhoneAudioSample/CellularWave.h b/audio/sysvad/PhoneAudioSample/CellularWave.h
deleted file mode 100644
index 1704ff0c..00000000
--- a/audio/sysvad/PhoneAudioSample/CellularWave.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- cellularwave.h
-
-Abstract:
-
- Definition of wavert miniport class for cellular
-
---*/
-
-#include "MinWaveRT.h"
-
-#ifndef _SYSVAD_CELLULARMINWAVERT_H_
-#define _SYSVAD_CELLULARMINWAVERT_H_
-
-NTSTATUS
-CreateCellularMiniportWaveRT
-(
- _Out_ PUNKNOWN * Unknown,
- _In_ REFCLSID,
- _In_opt_ PUNKNOWN UnknownOuter,
- _When_((PoolType & NonPagedPoolMustSucceed) != 0,
- __drv_reportError("Must succeed pool allocations are forbidden. "
- "Allocation failures cause a system crash"))
- _In_ POOL_TYPE PoolType,
- _In_ PUNKNOWN UnknownAdapter,
- _In_opt_ PVOID DeviceContext,
- _In_ PENDPOINT_MINIPAIR MiniportPair
-);
-
-//=============================================================================
-// Classes
-//=============================================================================
-///////////////////////////////////////////////////////////////////////////////
-// CCellularMiniportWaveRT
-//
-class CCellularMiniportWaveRT :
- public CMiniportWaveRT,
- public IAdapterPowerManagement
-{
-private:
- ULONG m_TelephonyProviderId;
- TELEPHONY_CALLTYPE m_TelephonyCallType;
- TELEPHONY_CALLTYPE m_PreviousTelephonyCallType;
- TELEPHONY_CALLSTATE m_TelephonyCallState;
- BOOL m_bTelephonyHold;
- BOOL m_bTelephonyMuteTx;
-
-public:
- DECLARE_STD_UNKNOWN();
- IMP_IAdapterPowerManagement;
-
- CCellularMiniportWaveRT(
- _In_ PUNKNOWN UnknownAdapter,
- _In_ PENDPOINT_MINIPAIR MiniportPair,
- _In_opt_ PVOID DeviceContext
- )
- :CMiniportWaveRT(UnknownAdapter, MiniportPair, DeviceContext),
- m_TelephonyProviderId(0),
- m_TelephonyCallType(TELEPHONY_CALLTYPE_CIRCUITSWITCHED),
- m_PreviousTelephonyCallType(TELEPHONY_CALLTYPE_CIRCUITSWITCHED),
- m_TelephonyCallState(TELEPHONY_CALLSTATE_DISABLED),
- m_bTelephonyHold(FALSE),
- m_bTelephonyMuteTx(FALSE)
- {
- if (IsCellularDevice())
- {
- if (m_DeviceFlags & ENDPOINT_CELLULAR_PROVIDER1)
- {
- m_TelephonyProviderId = 0;
- }
- else if (m_DeviceFlags & ENDPOINT_CELLULAR_PROVIDER2)
- {
- m_TelephonyProviderId = 1;
- }
- }
- }
-
- ~CCellularMiniportWaveRT();
-
- friend NTSTATUS PropertyHandler_CellularWaveFilter
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
-public:
- NTSTATUS PropertyHandler_TelephonyProviderId
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
- NTSTATUS PropertyHandler_TelephonyCallInfo
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
- NTSTATUS PropertyHandler_TelephonyCallState
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
- NTSTATUS PropertyHandler_TelephonyCallHold
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
- NTSTATUS PropertyHandler_TelephonyMuteTx
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
-private:
- NTSTATUS UpdateTopologyJackState
- (
- _In_ ULONG TelephonyId,
- _In_ BOOL NewState
- );
-};
-typedef CCellularMiniportWaveRT *PCCellularMiniportWaveRT;
-
-#endif // _SYSVAD_CELLULARMINWAVERT_H_
-
diff --git a/audio/sysvad/PhoneAudioSample/Cellulartopo.cpp b/audio/sysvad/PhoneAudioSample/Cellulartopo.cpp
deleted file mode 100644
index 7329a9f9..00000000
--- a/audio/sysvad/PhoneAudioSample/Cellulartopo.cpp
+++ /dev/null
@@ -1,1117 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- cellulartopo.cpp
-
-Abstract:
-
- Implementation of topology miniport for the cellular endpoint.
-
---*/
-
-#pragma warning (disable : 4127)
-
-#include <sysvad.h>
-#include "simple.h"
-#include "mintopo.h"
-#include "cellulartopo.h"
-#include "cellulartoptable.h"
-#include <ntstrsafe.h>
-
-
-#pragma code_seg("PAGE")
-
-
-// table of valid render/capture combinations for cellular routing.
-// speaker and mic (speakerphone)
-// headset speaker and headset mic (wired headset)
-// headset speaker and mic (wired headset without microphone)
-// handset speaker and handset mic (handset)
-// HFP speaker and HFP mic (bluetooth hands free)
-// special host routing pair
-KSTOPOLOGY_ENDPOINTIDPAIR g_EndpointList[] =
-{
- { HANDSET_SPEAKER_TOPONAME, KSPIN_TOPO_LINEOUT_DEST, HANDSET_MIC_TOPONAME, KSPIN_TOPO_MIC_ELEMENTS },
- { SPEAKER_TOPONAME, KSPIN_TOPO_LINEOUT_DEST, MIC_ARRAY1_TOPONAME, KSPIN_TOPO_MIC_ELEMENTS },
- { SPEAKER_HEADSET_TOPONAME, KSPIN_TOPO_LINEOUT_DEST, MIC_HEADSET_TOPONAME, KSPIN_TOPO_MIC_ELEMENTS },
- { SPEAKER_HEADSET_TOPONAME, KSPIN_TOPO_LINEOUT_DEST, MIC_ARRAY1_TOPONAME, KSPIN_TOPO_MIC_ELEMENTS },
- { HFP_SPEAKER_TOPONAME, KSPIN_TOPO_LINEOUT_DEST, HFP_MIC_TOPONAME, KSPIN_TOPO_MIC_ELEMENTS },
- { HOSTRENDER_TOPONAME, HOSTRENDER_PIN, HOSTCAPTURE_TOPONAME, HOSTCAPTURE_PIN }
-};
-
-//=============================================================================
-NTSTATUS
-CreateCellularMiniportTopology
-(
- _Out_ PUNKNOWN * Unknown,
- _In_ REFCLSID,
- _In_opt_ PUNKNOWN UnknownOuter,
- _When_((PoolType & NonPagedPoolMustSucceed) != 0,
- __drv_reportError("Must succeed pool allocations are forbidden. "
- "Allocation failures cause a system crash"))
- _In_ POOL_TYPE PoolType,
- _In_ PUNKNOWN UnknownAdapter,
- _In_opt_ PVOID DeviceContext,
- _In_ PENDPOINT_MINIPAIR MiniportPair
-)
-/*++
-
-Routine Description:
-
- Creates a new topology miniport.
-
-Arguments:
-
- Unknown -
-
- RefclsId -
-
- UnknownOuter -
-
- PoolType -
-
- UnknownAdapter -
-
- DeviceContext -
-
- MiniportPair -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(Unknown);
- ASSERT(MiniportPair);
-
- UNREFERENCED_PARAMETER(UnknownAdapter);
- UNREFERENCED_PARAMETER(DeviceContext);
-
- CCellularMiniportTopology *obj =
- new (PoolType, MINWAVERT_POOLTAG)
- CCellularMiniportTopology( UnknownOuter,
- MiniportPair->TopoDescriptor,
- MiniportPair->DeviceMaxChannels);
- if (NULL == obj)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- obj->AddRef();
- *Unknown = reinterpret_cast<IUnknown*>(obj);
-
- return STATUS_SUCCESS;
-} // CreateCellularMiniportTopology
-
-CCellularMiniportTopology::CCellularMiniportTopology
-(
- _In_opt_ PUNKNOWN UnknownOuter,
- _In_ PCFILTER_DESCRIPTOR *FilterDesc,
- _In_ USHORT DeviceMaxChannels
-)
-: CUnknown(UnknownOuter),
- CMiniportTopologySYSVAD(FilterDesc, DeviceMaxChannels),
- m_CellularVolume(0)
-{
- PAGED_CODE();
-
- InitializeListHead(&m_EndpointPairs);
-
- // populate the initial state
- memcpy(&m_CellularRenderEndpoint, &(g_EndpointList[0].RenderEndpoint), sizeof(m_CellularRenderEndpoint));
- memcpy(&m_CellularCaptureEndpoint, &(g_EndpointList[0].CaptureEndpoint), sizeof(m_CellularCaptureEndpoint));
-}
-
-
-//=============================================================================
-CCellularMiniportTopology::~CCellularMiniportTopology
-(
- void
-)
-/*++
-
-Routine Description:
-
- Topology miniport destructor
-
-Arguments:
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- while (!IsListEmpty(&m_EndpointPairs))
- {
- PLIST_ENTRY le = RemoveHeadList(&m_EndpointPairs);
- ENDPOINT_PAIR_ENTRY *pRecord = CONTAINING_RECORD(le, ENDPOINT_PAIR_ENTRY, ListEntry);
- delete pRecord;
- }
-
- DPF_ENTER(("[CCellularMiniportTopology::~CCellularMiniportTopology]"));
-} // ~CCellularMiniportTopology
-
-//=============================================================================
-NTSTATUS
-CCellularMiniportTopology::DataRangeIntersection
-(
- _In_ ULONG PinId,
- _In_ PKSDATARANGE ClientDataRange,
- _In_ PKSDATARANGE MyDataRange,
- _In_ ULONG OutputBufferLength,
- _Out_writes_bytes_to_opt_(OutputBufferLength, *ResultantFormatLength)
- PVOID ResultantFormat OPTIONAL,
- _Out_ PULONG ResultantFormatLength
-)
-/*++
-
-Routine Description:
-
- The DataRangeIntersection function determines the highest quality
- intersection of two data ranges.
-
-Arguments:
-
- PinId - Pin for which data intersection is being determined.
-
- ClientDataRange - Pointer to KSDATARANGE structure which contains the data range
- submitted by client in the data range intersection property
- request.
-
- MyDataRange - Pin's data range to be compared with client's data range.
-
- OutputBufferLength - Size of the buffer pointed to by the resultant format
- parameter.
-
- ResultantFormat - Pointer to value where the resultant format should be
- returned.
-
- ResultantFormatLength - Actual length of the resultant format that is placed
- at ResultantFormat. This should be less than or equal
- to OutputBufferLength.
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- return
- CMiniportTopologySYSVAD::DataRangeIntersection
- (
- PinId,
- ClientDataRange,
- MyDataRange,
- OutputBufferLength,
- ResultantFormat,
- ResultantFormatLength
- );
-} // DataRangeIntersection
-
-//=============================================================================
-STDMETHODIMP
-CCellularMiniportTopology::GetDescription
-(
- _Out_ PPCFILTER_DESCRIPTOR * OutFilterDescriptor
-)
-/*++
-
-Routine Description:
-
- The GetDescription function gets a pointer to a filter description.
- It provides a location to deposit a pointer in miniport's description
- structure. This is the placeholder for the FromNode or ToNode fields in
- connections which describe connections to the filter's pins.
-
-Arguments:
-
- OutFilterDescriptor - Pointer to the filter description.
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(OutFilterDescriptor);
-
- return CMiniportTopologySYSVAD::GetDescription(OutFilterDescriptor);
-} // GetDescription
-
-//=============================================================================
-STDMETHODIMP
-CCellularMiniportTopology::Init
-(
- _In_ PUNKNOWN UnknownAdapter,
- _In_ PRESOURCELIST ResourceList,
- _In_ PPORTTOPOLOGY Port_
-)
-/*++
-
-Routine Description:
-
- The Init function initializes the miniport. Callers of this function
- should run at IRQL PASSIVE_LEVEL
-
-Arguments:
-
- UnknownAdapter - A pointer to the Iuknown interface of the adapter object.
-
- ResourceList - Pointer to the resource list to be supplied to the miniport
- during initialization. The port driver is free to examine the
- contents of the ResourceList. The port driver will not be
- modify the ResourceList contents.
-
- Port - Pointer to the topology port object that is linked with this miniport.
-
-Return Value:
-
- NT status code.
-
---*/
-{
- UNREFERENCED_PARAMETER(ResourceList);
-
- PAGED_CODE();
-
- ASSERT(UnknownAdapter);
- ASSERT(Port_);
-
- DPF_ENTER(("[CCellularMiniportTopology::Init]"));
-
- NTSTATUS ntStatus = STATUS_SUCCESS;
-
- ExInitializeFastMutex(&m_EndpointFastMutex);
-
- // copy the full static list over to the dynamic list.
- for (int i = 0; i < SIZEOF_ARRAY(g_EndpointList) && NT_SUCCESS(ntStatus); i++)
- {
- ENDPOINT_PAIR_ENTRY *newEntry = new(NonPagedPoolNx, MINADAPTER_POOLTAG) ENDPOINT_PAIR_ENTRY;
-
- if (!newEntry)
- {
- DPF(D_TERSE, ("Insufficient memory to create endpoint pair"));
- ntStatus = STATUS_INSUFFICIENT_RESOURCES;
- }
- else
- {
- memcpy(&(newEntry->data), &(g_EndpointList[i]), sizeof(KSTOPOLOGY_ENDPOINTIDPAIR));
- InsertTailList(&m_EndpointPairs, &newEntry->ListEntry);
- }
- }
-
- if (NT_SUCCESS(ntStatus))
- {
- ntStatus =
- CMiniportTopologySYSVAD::Init
- (
- UnknownAdapter,
- Port_
- );
- }
-
- return ntStatus;
-} // Init
-
-//=============================================================================
-STDMETHODIMP
-CCellularMiniportTopology::NonDelegatingQueryInterface
-(
- _In_ REFIID Interface,
- _COM_Outptr_ PVOID * Object
-)
-/*++
-
-Routine Description:
-
- QueryInterface for MiniportTopology
-
-Arguments:
-
- Interface - GUID of the interface
-
- Object - interface object to be returned.
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(Object);
-
- if (IsEqualGUIDAligned(Interface, IID_IUnknown))
- {
- *Object = PVOID(PUNKNOWN(static_cast<IMiniportTopology*>( this )));
- }
- else if (IsEqualGUIDAligned(Interface, IID_IMiniport))
- {
- *Object = PVOID(PMINIPORT(this));
- }
- else if (IsEqualGUIDAligned(Interface, IID_IMiniportTopology))
- {
- *Object = PVOID(PMINIPORTTOPOLOGY(this));
- }
- else if (IsEqualGUIDAligned(Interface, IID_ICellularTopology))
- {
- *Object = PVOID(PCELLULARTOPOLOGY(this));
- }
- else if (IsEqualGUIDAligned(Interface, IID_IMiniportChange))
- {
- *Object = PVOID(static_cast<PMINIPORTCHANGE>( this ));
- }
- else
- {
- *Object = NULL;
- }
-
- if (*Object)
- {
- // We reference the interface for the caller.
- PUNKNOWN(*Object)->AddRef();
- return(STATUS_SUCCESS);
- }
-
- return(STATUS_INVALID_PARAMETER);
-} // NonDelegatingQueryInterface
-
-//=============================================================================
-NTSTATUS
-CCellularMiniportTopology::PropertyHandlerJackDescription
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION )
-
-Arguments:
-
- PropertyRequest
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandlerJackDescription]"));
-
- ULONG cJackDescriptions = ARRAYSIZE(CellularJackDescriptions);
- PKSJACK_DESCRIPTION * JackDescriptions = CellularJackDescriptions;
-
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- ULONG nPinId = (ULONG)-1;
-
- if (PropertyRequest->InstanceSize >= sizeof(ULONG))
- {
- nPinId = *(PULONG(PropertyRequest->Instance));
-
- if ((nPinId < cJackDescriptions) && (JackDescriptions[nPinId] != NULL))
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ntStatus =
- PropertyHandler_BasicSupport
- (
- PropertyRequest,
- KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
- VT_ILLEGAL
- );
- }
- else
- {
- ULONG cbNeeded = sizeof(KSMULTIPLE_ITEM) + sizeof(KSJACK_DESCRIPTION);
-
- if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = cbNeeded;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else if (PropertyRequest->ValueSize < cbNeeded)
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- PKSMULTIPLE_ITEM pMI = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
- PKSJACK_DESCRIPTION pDesc = (PKSJACK_DESCRIPTION)(pMI+1);
-
- pMI->Size = cbNeeded;
- pMI->Count = 1;
-
- RtlCopyMemory(pDesc, JackDescriptions[nPinId], sizeof(KSJACK_DESCRIPTION));
- ntStatus = STATUS_SUCCESS;
- }
- }
- }
- }
- }
-
- return ntStatus;
-}
-
-//=============================================================================
-NTSTATUS
-CCellularMiniportTopology::PropertyHandlerJackDescription2
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION2 )
-
-Arguments:
-
- PropertyRequest -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandlerJackDescription2]"));
-
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- ULONG nPinId = (ULONG)-1;
-
- ULONG cJackDescriptions = ARRAYSIZE(CellularJackDescriptions);
- PKSJACK_DESCRIPTION * JackDescriptions = CellularJackDescriptions;
-
- if (PropertyRequest->InstanceSize >= sizeof(ULONG))
- {
- nPinId = *(PULONG(PropertyRequest->Instance));
-
- if ((nPinId < cJackDescriptions) && (JackDescriptions[nPinId] != NULL))
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ntStatus =
- PropertyHandler_BasicSupport
- (
- PropertyRequest,
- KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
- VT_ILLEGAL
- );
- }
- else
- {
- ULONG cbNeeded = sizeof(KSMULTIPLE_ITEM) + sizeof(KSJACK_DESCRIPTION2);
-
- if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = cbNeeded;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else if (PropertyRequest->ValueSize < cbNeeded)
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- PKSMULTIPLE_ITEM pMI = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
- PKSJACK_DESCRIPTION2 pDesc = (PKSJACK_DESCRIPTION2)(pMI+1);
-
- pMI->Size = cbNeeded;
- pMI->Count = 1;
-
- RtlZeroMemory(pDesc, sizeof(KSJACK_DESCRIPTION2));
-
- //
- // Specifies the lower 16 bits of the DWORD parameter. This parameter indicates whether
- // the jack is currently active, streaming, idle, or hardware not ready.
- //
- pDesc->DeviceStateInfo = 0;
-
- //
- // From MSDN:
- // "If an audio device lacks jack presence detection, the IsConnected member of
- // the KSJACK_DESCRIPTION structure must always be set to TRUE. To remove the
- // ambiguity that results from this dual meaning of the TRUE value for IsConnected,
- // a client application can call IKsJackDescription2::GetJackDescription2 to read
- // the JackCapabilities flag of the KSJACK_DESCRIPTION2 structure. If this flag has
- // the JACKDESC2_PRESENCE_DETECT_CAPABILITY bit set, it indicates that the endpoint
- // does in fact support jack presence detection. In that case, the return value of
- // the IsConnected member can be interpreted to accurately reflect the insertion status
- // of the jack."
- //
- // Bit definitions:
- // 0x00000001 - JACKDESC2_PRESENCE_DETECT_CAPABILITY
- // 0x00000002 - JACKDESC2_DYNAMIC_FORMAT_CHANGE_CAPABILITY
- //
- pDesc->JackCapabilities = JACKDESC2_PRESENCE_DETECT_CAPABILITY;
-
- ntStatus = STATUS_SUCCESS;
- }
- }
- }
- }
- }
-
- return ntStatus;
-}
-
-//=============================================================================
-NTSTATUS
-CCellularMiniportTopology::PropertyHandlerTelephonyEndpointIdPair
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Handles ( KSPROPSETID_TelephonyTopology, KSPROPERTY_TELEPHONY_ENDPOINTIDPAIR )
-
-Arguments:
-
- PropertyRequest -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandlerTelephonyEndpointIdPair]"));
-
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
-
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- ULONG ulExpectedSize = (sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER));
-
- PLIST_ENTRY le = NULL;
- int countOfValidEndpointPairs = 0;
-
- ExAcquireFastMutex(&m_EndpointFastMutex);
-
- for (le = m_EndpointPairs.Flink; le != &m_EndpointPairs; le = le->Flink)
- {
- countOfValidEndpointPairs++;
- }
- ulExpectedSize += (countOfValidEndpointPairs * sizeof(KSTOPOLOGY_ENDPOINTIDPAIR));
-
- if (PropertyRequest->ValueSize >= sizeof(KSPROPERTY_DESCRIPTION))
- {
- // if return buffer can hold a KSPROPERTY_DESCRIPTION, return it
- //
- PKSPROPERTY_DESCRIPTION PropDesc =
- PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
-
- PropDesc->AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_SET |KSPROPERTY_TYPE_GET;
- PropDesc->DescriptionSize = ulExpectedSize;
- PropDesc->PropTypeSet.Set = KSPROPSETID_TelephonyTopology;
- PropDesc->PropTypeSet.Id = KSPROPERTY_TELEPHONY_ENDPOINTIDPAIR;
- PropDesc->MembersListCount = 0;
- PropDesc->PropTypeSet.Flags = 0;
- PropDesc->Reserved = 0;
-
- // buffer is big enough to hold the full data, add that
- if (PropertyRequest->ValueSize >= ulExpectedSize)
- {
- PKSPROPERTY_MEMBERSHEADER MembersHeader =
- PKSPROPERTY_MEMBERSHEADER(PropDesc + 1);
-
- // we're now adding the members header.
- PropDesc->MembersListCount = 1;
-
- MembersHeader->MembersFlags = KSPROPERTY_MEMBER_VALUES;
- MembersHeader->MembersSize = sizeof(KSTOPOLOGY_ENDPOINTIDPAIR);
- MembersHeader->MembersCount = countOfValidEndpointPairs;
- MembersHeader->Flags = 0;
-
- le = NULL;
- PKSTOPOLOGY_ENDPOINTIDPAIR returnData = (PKSTOPOLOGY_ENDPOINTIDPAIR) (MembersHeader + 1);
-
- for (le = m_EndpointPairs.Flink; le != &m_EndpointPairs; le = le->Flink)
- {
- ENDPOINT_PAIR_ENTRY *pRecord = CONTAINING_RECORD(le, ENDPOINT_PAIR_ENTRY, ListEntry);
- memcpy(returnData, &(pRecord->data), sizeof(pRecord->data));
- returnData++;
- }
-
- // tell them how much space we really used, which controls how much data is copied into the user buffer.
- PropertyRequest->ValueSize = ulExpectedSize;
- }
- else
- {
- // tell them how much space we really used, which controls how much data is copied into the user buffer.
- PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION);
- }
-
- ntStatus = STATUS_SUCCESS;
- }
- else if (PropertyRequest->ValueSize >= sizeof(ULONG))
- {
- // if return buffer can hold a ULONG, return the access flags.
- *(PULONG(PropertyRequest->Value)) = KSPROPERTY_TYPE_SET |KSPROPERTY_TYPE_GET;
- PropertyRequest->ValueSize = sizeof(ULONG);
- ntStatus = STATUS_SUCCESS;
- }
- else if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = ulExpectedSize;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
-
- ExReleaseFastMutex(&m_EndpointFastMutex);
- }
- else
- {
- ULONG cbNeeded = sizeof(KSTOPOLOGY_ENDPOINTIDPAIR);
-
- if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = cbNeeded;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else if (PropertyRequest->ValueSize < cbNeeded)
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- PKSTOPOLOGY_ENDPOINTIDPAIR EndpointIdPair = static_cast<PKSTOPOLOGY_ENDPOINTIDPAIR>(PropertyRequest->Value);
-
- // Return endpoints (render and capture) info where cellular audio is being routed to.
- memcpy(&(EndpointIdPair->RenderEndpoint), &m_CellularRenderEndpoint, sizeof(m_CellularRenderEndpoint));
- memcpy(&(EndpointIdPair->CaptureEndpoint), &m_CellularCaptureEndpoint, sizeof(m_CellularCaptureEndpoint));
-
- ntStatus = STATUS_SUCCESS;
- }
- else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
- {
- PKSTOPOLOGY_ENDPOINTIDPAIR EndpointIdPair = static_cast<PKSTOPOLOGY_ENDPOINTIDPAIR>(PropertyRequest->Value);
- PLIST_ENTRY le = NULL;
-
- // verify the requested combination is in the list of valid endpoint combinations, fail with
- // invalid parameter if not found.
- ntStatus = STATUS_INVALID_PARAMETER;
-
- ExAcquireFastMutex(&m_EndpointFastMutex);
-
- for (le = m_EndpointPairs.Flink; le != &m_EndpointPairs; le = le->Flink)
- {
- ENDPOINT_PAIR_ENTRY *pRecord = CONTAINING_RECORD(le, ENDPOINT_PAIR_ENTRY, ListEntry);
-
- if (pRecord->data.RenderEndpoint.PinId == EndpointIdPair->RenderEndpoint.PinId &&
- 0 == _wcsnicmp(pRecord->data.RenderEndpoint.TopologyName, EndpointIdPair->RenderEndpoint.TopologyName, MAX_PATH) &&
- pRecord->data.CaptureEndpoint.PinId == EndpointIdPair->CaptureEndpoint.PinId &&
- 0 == _wcsnicmp(pRecord->data.CaptureEndpoint.TopologyName, EndpointIdPair->CaptureEndpoint.TopologyName, MAX_PATH))
- {
- if (HOSTRENDER_PIN == EndpointIdPair->RenderEndpoint.PinId &&
- 0 == _wcsnicmp(HOSTRENDER_TOPONAME, EndpointIdPair->RenderEndpoint.TopologyName, MAX_PATH) &&
- HOSTCAPTURE_PIN == EndpointIdPair->CaptureEndpoint.PinId &&
- 0 == _wcsnicmp(HOSTCAPTURE_TOPONAME, EndpointIdPair->CaptureEndpoint.TopologyName, MAX_PATH))
- {
- // This is an indication that cellular audio is being routed through OS (For example, user plugs in USB headset
- // for cellular audio) and driver must stop rendering cellular audio to any physical audio endpoint. Driver must
- // also stop capturing data from any physical audio endpoint for cellular. This will update audio routing for
- // all the active cellular calls.
- }
- else
- {
- // Route cellular audio to these new endpoints (render and capture). This will update audio routing for
- // all the active cellular calls.
- }
-
- memcpy(&m_CellularRenderEndpoint, &(EndpointIdPair->RenderEndpoint), sizeof(m_CellularRenderEndpoint));
- memcpy(&m_CellularCaptureEndpoint, &(EndpointIdPair->CaptureEndpoint), sizeof(m_CellularCaptureEndpoint));
-
- // we found the entry, so return success
- ntStatus = STATUS_SUCCESS;
- break;
- }
- }
-
- ExReleaseFastMutex(&m_EndpointFastMutex);
- }
- else
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- }
-
- return ntStatus;
-}
-
-//=============================================================================
-NTSTATUS
-CCellularMiniportTopology::PropertyHandlerTelephonyVolume
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Handles ( KSPROPSETID_TelephonyTopology, KSPROPERTY_TELEPHONY_VOLUME )
-
-Arguments:
-
- PropertyRequest -
-
-Return Value:
-
- NT status code.
-
---*/
-{
-
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandlerTelephonyVolume]"));
-
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
-
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ntStatus =
- PropertyHandler_BasicSupportVolume
- (
- PropertyRequest,
- 1 // Telephony audio is only ever 1 channel
- );
-
- ULONG cbFullProperty =
- sizeof(KSPROPERTY_DESCRIPTION) +
- sizeof(KSPROPERTY_MEMBERSHEADER) +
- sizeof(KSPROPERTY_STEPPING_LONG);
-
- if (NT_SUCCESS(ntStatus) && PropertyRequest->ValueSize >= cbFullProperty)
- {
- // Access proper values
- PKSPROPERTY_DESCRIPTION PropDesc =
- PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
- PKSPROPERTY_MEMBERSHEADER Members =
- PKSPROPERTY_MEMBERSHEADER(PropDesc + 1);
- PKSPROPERTY_STEPPING_LONG Range =
- PKSPROPERTY_STEPPING_LONG(Members + 1);
-
- // Telephony volume is only ever single channel, so the
- // MULTICHANNEL and UNIFORM flags are meaningless
- Members->Flags = 0;
-
- // Telephony Values that may be different from standard volume values
- Range->Bounds.SignedMaximum = TELEPHONY_VOLUME_MAXIMUM;
- Range->Bounds.SignedMinimum = TELEPHONY_VOLUME_MINIMUM;
- Range->SteppingDelta = TELEPHONY_VOLUME_STEPPING;
- }
- }
- else
- {
- ntStatus =
- ValidatePropertyParams
- (
- PropertyRequest,
- sizeof(LONG), // volume value is a LONG
- 0 // there is no channel associated with telephony volume
- );
-
-
- if (NT_SUCCESS(ntStatus))
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- LONG* volume = (LONG*)PropertyRequest->Value;
- // Return current cellular volume (Incall volume).
- *volume = m_CellularVolume;
- PropertyRequest->ValueSize = sizeof(LONG);
- ntStatus = STATUS_SUCCESS;
- }
- else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
- {
- LONG* volume = (LONG*)PropertyRequest->Value;
-
- LONG normalizedVolume =
- VALUE_NORMALIZE_IN_RANGE_EX
- (
- *volume,
- TELEPHONY_VOLUME_MINIMUM,
- TELEPHONY_VOLUME_MAXIMUM,
- TELEPHONY_VOLUME_STEPPING
- );
- if (normalizedVolume == *volume)
- {
- // Update the cellular volume (Incall volume). This will update cellular volume for all the active cellular calls.
- m_CellularVolume = *volume;
- ntStatus = STATUS_SUCCESS;
- }
- else
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- else
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- }
-
- return ntStatus;
-}
-
-//=============================================================================
-NTSTATUS
-PropertyHandler_CellularTopoFilter
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Redirects property request to miniport object
-
-Arguments:
-
- PropertyRequest -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandler_CellularTopoFilter]"));
-
- // PropertryRequest structure is filled by portcls.
- // MajorTarget is a pointer to miniport object for miniports.
- //
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- PCCellularMiniportTopology pMiniport = reinterpret_cast<PCCellularMiniportTopology>(PropertyRequest->MajorTarget);
-
- if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Jack))
- {
- if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION)
- {
- ntStatus = pMiniport->PropertyHandlerJackDescription(PropertyRequest);
- }
- else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION2)
- {
- ntStatus = pMiniport->PropertyHandlerJackDescription2(PropertyRequest);
- }
- }
- else if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_TelephonyTopology))
- {
- if (PropertyRequest->PropertyItem->Id == KSPROPERTY_TELEPHONY_ENDPOINTIDPAIR)
- {
- ntStatus = pMiniport->PropertyHandlerTelephonyEndpointIdPair(PropertyRequest);
- }
- else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_TELEPHONY_VOLUME)
- {
- ntStatus = pMiniport->PropertyHandlerTelephonyVolume(PropertyRequest);
- }
- }
-
- return ntStatus;
-} // PropertyHandler_CellularTopoFilter
-
-#pragma code_seg("PAGE")
-STDMETHODIMP_(NTSTATUS)
-CCellularMiniportTopology::UpdateTopologyJackState
-(
- _In_ ULONG TelephonyId,
- _In_ BOOL NewState
-)
-{
- PAGED_CODE ();
-
- struct JackState
- {
- ULONG TelephonyId;
- ULONG PinId;
- PKSJACK_DESCRIPTION JackControl;
- };
-
- JackState Jacks[] =
- {
- {
- 0,
- KSPIN_TOPO_BIDI1,
- &CellularJackDesc
- },
- {
- 1,
- KSPIN_TOPO_BIDI2,
- &CellularJackDesc2
- }
- };
-
- // Query the registry and update the jack state for all of the pins.
- for (int i = 0; i < SIZEOF_ARRAY(Jacks); i++)
- {
- if (Jacks[i].TelephonyId == TelephonyId)
- {
- Jacks[i].JackControl->IsConnected = NewState;
-
- // we have multiple pins which share the same jack state,
- // notify for every pin using that jack state
- GenerateEventList(
- (GUID*)&KSEVENTSETID_PinCapsChange, // event set. NULL is a wild card for all events.
- KSEVENT_PINCAPS_JACKINFOCHANGE, // event ID.
- TRUE, // use pid ID.
- Jacks[i].PinId, // pin ID.
- FALSE, // do not use node ID.
- ULONG(-1)); // node ID, not used.
- }
- }
-
- return STATUS_SUCCESS;
-}
-
-#pragma code_seg()
-NTSTATUS CCellularMiniportWaveRT_EventHandler_JackState
-(
- _In_ PPCEVENT_REQUEST EventRequest
-)
-{
- CCellularMiniportTopology* miniport = reinterpret_cast<CCellularMiniportTopology*>(EventRequest->MajorTarget);
- return miniport->EventHandler_JackState(EventRequest);
-}
-
-NTSTATUS CCellularMiniportTopology::EventHandler_JackState
-(
- _In_ PPCEVENT_REQUEST EventRequest
-)
-{
- if (EventRequest->Verb == PCEVENT_VERB_ADD)
- {
- m_PortEvents->AddEventToEventList(EventRequest->EventEntry);
- }
-
- return STATUS_SUCCESS;
-}
-
-#pragma code_seg("PAGE")
-STDMETHODIMP_(NTSTATUS)
-CCellularMiniportTopology::NotifyEndpointPair
-(
- _In_ WCHAR *RenderEndpointTopoName,
- _In_ ULONG RenderEndpointNameLen,
- _In_ ULONG RenderPinId,
- _In_ WCHAR *CaptureEndpointTopoName,
- _In_ ULONG CaptureEndpointNameLen,
- _In_ ULONG CapturePinId
-)
-{
- PAGED_CODE ();
-
- NTSTATUS ntStatus = STATUS_SUCCESS;
-
- ENDPOINT_PAIR_ENTRY *newEntry = new(NonPagedPoolNx, MINADAPTER_POOLTAG) ENDPOINT_PAIR_ENTRY;
-
- if (!newEntry)
- {
- DPF(D_TERSE, ("Insufficient memory to create endpoint pair"));
- ntStatus = STATUS_INSUFFICIENT_RESOURCES;
- }
-
- if (NT_SUCCESS(ntStatus))
- {
- KSTOPOLOGY_ENDPOINTIDPAIR *endpointPair = &newEntry->data;
-
- RtlStringCchCopyNW(endpointPair->RenderEndpoint.TopologyName,
- SIZEOF_ARRAY(endpointPair->RenderEndpoint.TopologyName),
- RenderEndpointTopoName,
- RenderEndpointNameLen);
- endpointPair->RenderEndpoint.PinId = RenderPinId;
-
- RtlStringCchCopyNW(endpointPair->CaptureEndpoint.TopologyName,
- SIZEOF_ARRAY(endpointPair->CaptureEndpoint.TopologyName),
- CaptureEndpointTopoName,
- CaptureEndpointNameLen);
- endpointPair->CaptureEndpoint.PinId = CapturePinId;
-
- ExAcquireFastMutex(&m_EndpointFastMutex);
- InsertTailList(&m_EndpointPairs, &newEntry->ListEntry);
- ExReleaseFastMutex(&m_EndpointFastMutex);
-
- GenerateEventList(
- (GUID*)&KSEVENTSETID_Telephony,
- KSEVENT_TELEPHONY_ENDPOINTPAIRS_CHANGED,
- FALSE,
- NULL,
- FALSE,
- ULONG(-1));
- }
-
- return ntStatus;
-}
-
-#pragma code_seg()
-NTSTATUS CCellularMiniportWaveRT_EventHandler_Telephony
-(
- _In_ PPCEVENT_REQUEST EventRequest
-)
-{
- CCellularMiniportTopology* miniport = reinterpret_cast<CCellularMiniportTopology*>(EventRequest->MajorTarget);
- return miniport->EventHandler_Telephony(EventRequest);
-}
-
-NTSTATUS CCellularMiniportTopology::EventHandler_Telephony
-(
- _In_ PPCEVENT_REQUEST EventRequest
-)
-{
- if (EventRequest->Verb == PCEVENT_VERB_ADD)
- {
- m_PortEvents->AddEventToEventList(EventRequest->EventEntry);
- }
-
- return STATUS_SUCCESS;
-}
-
-
diff --git a/audio/sysvad/PhoneAudioSample/Cellulartopo.h b/audio/sysvad/PhoneAudioSample/Cellulartopo.h
deleted file mode 100644
index b898741c..00000000
--- a/audio/sysvad/PhoneAudioSample/Cellulartopo.h
+++ /dev/null
@@ -1,184 +0,0 @@
-
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- cellulartopo.h
-
-Abstract:
-
- Declaration of topology miniport for the cellular endpoint.
-
---*/
-
-#ifndef _SYSVAD_CELLULARTOPO_H_
-#define _SYSVAD_CELLULARTOPO_H_
-
-#include "basetopo.h"
-
-// make sure all of these names matches with KSNAME_* in the inf's [Strings] section
-#define SPEAKER_TOPONAME L"TopologySpeaker"
-#define SPEAKER_HEADSET_TOPONAME L"TopologySpeakerHeadset"
-#define MIC_HEADSET_TOPONAME L"TopologyMicHeadset"
-#define MIC_ARRAY1_TOPONAME L"TopologyMicArray1"
-#define HANDSET_SPEAKER_TOPONAME L"TopologyHandsetSpeaker"
-#define HANDSET_MIC_TOPONAME L"TopologyHandsetMic"
-
-// from bthhfpminipairs.h, static name of bluetooth speaker and mic topologies
-#define HFP_SPEAKER_TOPONAME L"TopologyBthHfpSpeaker"
-#define HFP_MIC_TOPONAME L"TopologyBthHfpMic"
-
-// Special routing endpoints
-#define HOSTRENDER_TOPONAME L"HostRender"
-#define HOSTRENDER_PIN 0
-#define HOSTCAPTURE_TOPONAME L"HostCapture"
-#define HOSTCAPTURE_PIN 0
-
-// Telephony Volume Stepping information
-#define TELEPHONY_VOLUME_MAXIMUM 0 // 0 dB
-#define TELEPHONY_VOLUME_MINIMUM (-30 * 0x10000) // -30 dB
-#define TELEPHONY_VOLUME_STEPPING (3 * 0x10000) // 10 steps
-
-
-typedef struct _ENDPOINT_PAIR_ENTRY
-{
- LIST_ENTRY ListEntry;
- KSTOPOLOGY_ENDPOINTIDPAIR data;
-} ENDPOINT_PAIR_ENTRY;
-
-//=============================================================================
-// Defines
-//=============================================================================
-// {3829F9C3-F341-4B82-976F-A635EB3CEA0D}
-DEFINE_GUID(IID_ICellularTopology,
-0x3829f9c3, 0xf341, 0x4b82, 0x97, 0x6f, 0xa6, 0x35, 0xeb, 0x3c, 0xea, 0xd);
-
-
-//=============================================================================
-// Interfaces
-//=============================================================================
-
-///////////////////////////////////////////////////////////////////////////////
-// ICellularTopology
-//
-DECLARE_INTERFACE_(ICellularTopology, IMiniportTopology)
-{
- STDMETHOD_(NTSTATUS, UpdateTopologyJackState)
- (
- THIS_
- _In_ ULONG TelephonyId,
- _In_ BOOL NewState
- ) PURE;
-};
-
-typedef ICellularTopology *PCELLULARTOPOLOGY;
-
-//=============================================================================
-// Classes
-//=============================================================================
-
-///////////////////////////////////////////////////////////////////////////////
-// CCellularMiniportTopology
-//
-
-class CCellularMiniportTopology :
- public CMiniportTopologySYSVAD,
- public ICellularTopology,
- public IMiniportChange,
- public CUnknown
-{
- private:
- KSTOPOLOGY_ENDPOINTID m_CellularRenderEndpoint;
- KSTOPOLOGY_ENDPOINTID m_CellularCaptureEndpoint;
- ULONG m_CellularVolume;
-
- FAST_MUTEX m_EndpointFastMutex;
- LIST_ENTRY m_EndpointPairs;
-
- public:
- DECLARE_STD_UNKNOWN();
- CCellularMiniportTopology
- (
- _In_opt_ PUNKNOWN UnknownOuter,
- _In_ PCFILTER_DESCRIPTOR *FilterDesc,
- _In_ USHORT DeviceMaxChannels
- );
-
- ~CCellularMiniportTopology();
-
- IMP_IMiniportTopology;
-
- NTSTATUS PropertyHandlerJackSinkInfo
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
- NTSTATUS PropertyHandlerJackDescription
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
- NTSTATUS PropertyHandlerJackDescription2
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
- NTSTATUS PropertyHandlerTelephonyEndpointIdPair
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
- NTSTATUS PropertyHandlerTelephonyVolume
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
- NTSTATUS EventHandler_JackState
- (
- _In_ PPCEVENT_REQUEST _pEventRequest
- );
-
- STDMETHODIMP_(NTSTATUS) UpdateTopologyJackState
- (
- _In_ ULONG TelephonyId,
- _In_ BOOL NewState
- );
-
- NTSTATUS EventHandler_Telephony
- (
- _In_ PPCEVENT_REQUEST _pEventRequest
- );
-
- STDMETHODIMP_(NTSTATUS) NotifyEndpointPair
- (
- _In_ WCHAR *RenderEndpointTopoName,
- _In_ ULONG RenderEndpointNameLen,
- _In_ ULONG RenderPinId,
- _In_ WCHAR *CaptureEndpointTopoName,
- _In_ ULONG CaptureEndpointNameLen,
- _In_ ULONG CapturePinId
- );
-};
-
-typedef CCellularMiniportTopology *PCCellularMiniportTopology;
-
-NTSTATUS
-CreateCellularMiniportTopology(
- _Out_ PUNKNOWN * Unknown,
- _In_ REFCLSID,
- _In_opt_ PUNKNOWN UnknownOuter,
- _When_((PoolType & NonPagedPoolMustSucceed) != 0,
- __drv_reportError("Must succeed pool allocations are forbidden. "
- "Allocation failures cause a system crash"))
- _In_ POOL_TYPE PoolType,
- _In_ PUNKNOWN UnknownAdapter,
- _In_opt_ PVOID DeviceContext,
- _In_ PENDPOINT_MINIPAIR MiniportPair
- );
-
-NTSTATUS PropertyHandler_CellularTopoFilter(_In_ PPCPROPERTY_REQUEST PropertyRequest);
-
-#endif // _SYSVAD_CELLULARTOPO_H_
-
diff --git a/audio/sysvad/PhoneAudioSample/Cellulartoptable.h b/audio/sysvad/PhoneAudioSample/Cellulartoptable.h
deleted file mode 100644
index 53eef9ae..00000000
--- a/audio/sysvad/PhoneAudioSample/Cellulartoptable.h
+++ /dev/null
@@ -1,267 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- cellulartoptable.h
-
-Abstract:
-
- Declaration of topology tables for the cellular endpoint.
-
---*/
-
-#ifndef _SYSVAD_CELLULARTOPTABLE_H_
-#define _SYSVAD_CELLULARTOPTABLE_H_
-
-// {896BC350-BF57-4039-A6B6-64DCEC3AEEB8}
-DEFINE_GUID(CELLULARBIDI1_CUSTOM_NAME,
-0x896bc350, 0xbf57, 0x4039, 0xa6, 0xb6, 0x64, 0xdc, 0xec, 0x3a, 0xee, 0xb8);
-
-// {80CC64DA-166A-4A2C-ADF7-1464C49D3B0E}
-DEFINE_GUID(CELLULARBIDI2_CUSTOM_NAME,
-0x80cc64da, 0x166a, 0x4a2c, 0xad, 0xf7, 0x14, 0x64, 0xc4, 0x9d, 0x3b, 0xe);
-
-//=============================================================================
-static
-KSDATARANGE CellularTopoPinDataRangesBridge[] =
-{
- {
- sizeof(KSDATARANGE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
- }
-};
-
-//=============================================================================
-static
-PKSDATARANGE CellularTopoPinDataRangePointersBridge[] =
-{
- &CellularTopoPinDataRangesBridge[0]
-};
-
-//=============================================================================
-static
-PCPIN_DESCRIPTOR CellularTopoMiniportPins[] =
-{
- // KSPIN_TOPO_BIDI1
- {
- 0,
- 0,
- 0, // InstanceCount
- NULL, // AutomationTable
- { // KsPinDescriptor
- 0, // InterfacesCount
- NULL, // Interfaces
- 0, // MediumsCount
- NULL, // Mediums
- SIZEOF_ARRAY(CellularTopoPinDataRangePointersBridge), // DataRangesCount
- CellularTopoPinDataRangePointersBridge, // DataRanges
- KSPIN_DATAFLOW_IN, // DataFlow
- KSPIN_COMMUNICATION_NONE, // Communication
- &KSNODETYPE_TELEPHONY_BIDI, // Category
- &CELLULARBIDI1_CUSTOM_NAME, // Name
- 0 // Reserved
- }
- },
- // KSPIN_TOPO_BIDI1_BRIDGE
- {
- 0,
- 0,
- 0, // InstanceCount
- NULL, // AutomationTable
- { // KsPinDescriptor
- 0, // InterfacesCount
- NULL, // Interfaces
- 0, // MediumsCount
- NULL, // Mediums
- SIZEOF_ARRAY(CellularTopoPinDataRangePointersBridge), // DataRangesCount
- CellularTopoPinDataRangePointersBridge, // DataRanges
- KSPIN_DATAFLOW_OUT, // DataFlow
- KSPIN_COMMUNICATION_NONE, // Communication
- &KSCATEGORY_AUDIO, // Category
- NULL, // Name
- 0 // Reserved
- }
- },
- // KSPIN_TOPO_BIDI2
- {
- 0,
- 0,
- 0, // InstanceCount
- NULL, // AutomationTable
- { // KsPinDescriptor
- 0, // InterfacesCount
- NULL, // Interfaces
- 0, // MediumsCount
- NULL, // Mediums
- SIZEOF_ARRAY(CellularTopoPinDataRangePointersBridge), // DataRangesCount
- CellularTopoPinDataRangePointersBridge, // DataRanges
- KSPIN_DATAFLOW_IN, // DataFlow
- KSPIN_COMMUNICATION_NONE, // Communication
- &KSNODETYPE_TELEPHONY_BIDI, // Category
- &CELLULARBIDI2_CUSTOM_NAME, // Name
- 0 // Reserved
- }
- },
- // KSPIN_TOPO_BIDI2_BRIDGE
- {
- 0,
- 0,
- 0, // InstanceCount
- NULL, // AutomationTable
- { // KsPinDescriptor
- 0, // InterfacesCount
- NULL, // Interfaces
- 0, // MediumsCount
- NULL, // Mediums
- SIZEOF_ARRAY(CellularTopoPinDataRangePointersBridge), // DataRangesCount
- CellularTopoPinDataRangePointersBridge, // DataRanges
- KSPIN_DATAFLOW_OUT, // DataFlow
- KSPIN_COMMUNICATION_NONE, // Communication
- &KSCATEGORY_AUDIO, // Category
- NULL, // Name
- 0 // Reserved
- }
- }
-};
-
-//=============================================================================
-static
-KSJACK_DESCRIPTION CellularJackDesc =
-{
- KSAUDIO_SPEAKER_MONO,
- 0x0000, // no color
- eConnTypeUnknown,
- eGeoLocNotApplicable,
- eGenLocInternal,
- ePortConnUnknown,
- TRUE // NOTE: cellular jacks should be "unplugged" at boot, and only changed to active during a call.
- // However, for convienience during development, the jack state is set to active at boot for this milestone.
-};
-
-static
-KSJACK_DESCRIPTION CellularJackDesc2 =
-{
- KSAUDIO_SPEAKER_MONO,
- 0x0000, // no color
- eConnTypeUnknown,
- eGeoLocNotApplicable,
- eGenLocInternal,
- ePortConnUnknown,
- TRUE // NOTE: cellular jacks should be "unplugged" at boot, and only changed to active during a call.
- // However, for convienience during development, the jack state is set to active at boot for this milestone.
-};
-
-
-// Only return a KSJACK_DESCRIPTION for the physical bridge pin.
-static
-PKSJACK_DESCRIPTION CellularJackDescriptions[] =
-{
- &CellularJackDesc,
- NULL,
- &CellularJackDesc2,
- NULL
-};
-
-//=============================================================================
-static
-PCCONNECTION_DESCRIPTOR CellularTopoMiniportConnections[] =
-{
- // FromNode, FromPin, ToNode, ToPin
- { PCFILTER_NODE, KSPIN_TOPO_BIDI1, PCFILTER_NODE, KSPIN_TOPO_BIDI1_BRIDGE},
- { PCFILTER_NODE, KSPIN_TOPO_BIDI2, PCFILTER_NODE, KSPIN_TOPO_BIDI2_BRIDGE}
-};
-
-
-//=============================================================================
-static
-PCPROPERTY_ITEM PropertiesCellularTopoFilter[] =
-{
- {
- &KSPROPSETID_Jack,
- KSPROPERTY_JACK_DESCRIPTION,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_CellularTopoFilter
- },
- {
- &KSPROPSETID_Jack,
- KSPROPERTY_JACK_DESCRIPTION2,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_CellularTopoFilter
- },
- {
- &KSPROPSETID_TelephonyTopology,
- KSPROPERTY_TELEPHONY_ENDPOINTIDPAIR,
- KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_CellularTopoFilter
- },
- {
- &KSPROPSETID_TelephonyTopology,
- KSPROPERTY_TELEPHONY_VOLUME,
- KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_CellularTopoFilter
- }
-};
-
-NTSTATUS CCellularMiniportWaveRT_EventHandler_JackState
-(
- _In_ PPCEVENT_REQUEST EventRequest
-);
-
-NTSTATUS CCellularMiniportWaveRT_EventHandler_Telephony
-(
- _In_ PPCEVENT_REQUEST EventRequest
-);
-
-
-static PCEVENT_ITEM TelephonyEvents[] =
-{
- {
- &KSEVENTSETID_PinCapsChange, // Something changed
- KSEVENT_PINCAPS_JACKINFOCHANGE, // Jack Info Changes
- KSEVENT_TYPE_ENABLE | KSEVENT_TYPE_BASICSUPPORT,
- CCellularMiniportWaveRT_EventHandler_JackState
- },
- {
- &KSEVENTSETID_Telephony,
- KSEVENT_TELEPHONY_ENDPOINTPAIRS_CHANGED,
- KSEVENT_TYPE_ENABLE | KSEVENT_TYPE_BASICSUPPORT,
- CCellularMiniportWaveRT_EventHandler_Telephony
- }
-};
-
-/*****************************************************************************
- * PropertiesTopologyFilter
- *****************************************************************************
- * Automation table for jack descripton/detection.
- */
-DEFINE_PCAUTOMATION_TABLE_PROP_EVENT(AutomationCellularTopoFilter, PropertiesCellularTopoFilter, TelephonyEvents);
-
-
-//=============================================================================
-static
-PCFILTER_DESCRIPTOR CellularTopoMiniportFilterDescriptor =
-{
- 0, // Version
- &AutomationCellularTopoFilter, // AutomationTable
- sizeof(PCPIN_DESCRIPTOR), // PinSize
- SIZEOF_ARRAY(CellularTopoMiniportPins), // PinCount
- CellularTopoMiniportPins, // Pins
- sizeof(PCNODE_DESCRIPTOR), // NodeSize
- 0, // NodeCount
- NULL, // Nodes
- SIZEOF_ARRAY(CellularTopoMiniportConnections), // ConnectionCount
- CellularTopoMiniportConnections, // Connections
- 0, // CategoryCount
- NULL // Categories
-};
-
-#endif // _SYSVAD_CELLULARTOPTABLE_H_
-
-
diff --git a/audio/sysvad/PhoneAudioSample/Cellularwavtable.h b/audio/sysvad/PhoneAudioSample/Cellularwavtable.h
deleted file mode 100644
index 806cb05d..00000000
--- a/audio/sysvad/PhoneAudioSample/Cellularwavtable.h
+++ /dev/null
@@ -1,286 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- cellularwavtable.h
-
-Abstract:
-
- Declaration of wave miniport tables for the cellular endpoint.
-
---*/
-
-#ifndef _SYSVAD_CELLULARWAVTABLE_H_
-#define _SYSVAD_CELLULARWAVTABLE_H_
-
-
-#define CELLULAR_DEVICE_MAX_CHANNELS 1 // Max Channels.
-
-#define CELLULAR_CAPTURE_MAX_CHANNELS 1 // Max Channels.
-#define CELLULAR_CAPTURE_MIN_BITS_PER_SAMPLE 16 // Min Bits Per Sample
-#define CELLULAR_CAPTURE_MAX_BITS_PER_SAMPLE 16 // Max Bits Per Sample
-#define CELLULAR_CAPTURE_MIN_SAMPLE_RATE 16000 // Min Sample Rate
-#define CELLULAR_CAPTURE_MAX_SAMPLE_RATE 16000 // Max Sample Rate
-
-//
-// Max # of pin instances.
-//
-#define CELLULAR_MAX_INPUT_SYSTEM_STREAMS 1
-
-
-//=============================================================================
-static
-KSDATAFORMAT_WAVEFORMATEXTENSIBLE CellularCapturePinSupportedDeviceFormats[] =
-{
- { // 0
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 1,
- 16000,
- 32000,
- 2,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_MONO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
-};
-
-//
-// Supported modes (only on streaming pins).
-//
-static
-MODE_AND_DEFAULT_FORMAT CellularCapturePinSupportedDeviceModes[] =
-{
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_RAW,
- &CellularCapturePinSupportedDeviceFormats[SIZEOF_ARRAY(CellularCapturePinSupportedDeviceFormats) - 1].DataFormat
- }
-};
-
-//=============================================================================
-// The entries here must follow the same order as the filter's pin
-// descriptor array.
-//
-static
-PIN_DEVICE_FORMATS_AND_MODES CellularPinDeviceFormatsAndModes[] =
-{
- { // BIDI
- TelephonyBidiPin,
- CellularCapturePinSupportedDeviceFormats,
- SIZEOF_ARRAY(CellularCapturePinSupportedDeviceFormats),
- CellularCapturePinSupportedDeviceModes,
- SIZEOF_ARRAY(CellularCapturePinSupportedDeviceModes)
- },
- {
- BridgePin,
- NULL,
- 0,
- NULL,
- 0,
- }
-};
-
-//=============================================================================
-static
-KSDATARANGE_AUDIO CellularPinDataRangesStream[] =
-{
- { // 0
- {
- sizeof(KSDATARANGE_AUDIO),
- KSDATARANGE_ATTRIBUTES, // An attributes list follows this data range
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- CELLULAR_CAPTURE_MAX_CHANNELS,
- CELLULAR_CAPTURE_MIN_BITS_PER_SAMPLE,
- CELLULAR_CAPTURE_MAX_BITS_PER_SAMPLE,
- CELLULAR_CAPTURE_MIN_SAMPLE_RATE,
- CELLULAR_CAPTURE_MAX_SAMPLE_RATE
- }
-};
-
-static
-PKSDATARANGE CellularPinDataRangePointersBiDiStream[] =
-{
- PKSDATARANGE(&CellularPinDataRangesStream[0]),
- PKSDATARANGE(&PinDataRangeAttributeList)
-};
-
-//=============================================================================
-static
-KSDATARANGE CellularPinDataRangesBridge[] =
-{
- {
- sizeof(KSDATARANGE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
- }
-};
-
-static
-PKSDATARANGE CellularPinDataRangePointersBridge[] =
-{
- &CellularPinDataRangesBridge[0]
-};
-
-
-//=============================================================================
-static
-PCPIN_DESCRIPTOR CellularWaveMiniportPins[] =
-{
- // Wave Out Streaming Pin (Renderer) KSPIN_WAVE_BIDI
- {
- CELLULAR_MAX_INPUT_SYSTEM_STREAMS,
- CELLULAR_MAX_INPUT_SYSTEM_STREAMS,
- 0,
- NULL,
- {
- 0,
- NULL,
- 0,
- NULL,
- SIZEOF_ARRAY(CellularPinDataRangePointersBiDiStream),
- CellularPinDataRangePointersBiDiStream,
- KSPIN_DATAFLOW_OUT,
- KSPIN_COMMUNICATION_SINK,
- &KSCATEGORY_AUDIO,
- NULL,
- 0
- }
- },
- // Wave Out Bridge Pin (Renderer) KSPIN_WAVE_BIDI_BRIDGE
- {
- 0,
- 0,
- 0,
- NULL,
- {
- 0,
- NULL,
- 0,
- NULL,
- SIZEOF_ARRAY(CellularPinDataRangePointersBridge),
- CellularPinDataRangePointersBridge,
- KSPIN_DATAFLOW_IN,
- KSPIN_COMMUNICATION_NONE,
- &KSCATEGORY_AUDIO,
- NULL,
- 0
- }
- }
-};
-
-//=============================================================================
-//
-// Note:
-//
-// -----
-// | |
-// BiDi pin 1 <--| |<-- 0 BiDi bridge pin
-// -----
-
-static
-PCCONNECTION_DESCRIPTOR CellularWaveMiniportConnections[] =
-{
- { PCFILTER_NODE, KSPIN_WAVE_BIDI_BRIDGE, PCFILTER_NODE, KSPIN_WAVE_BIDI }
-};
-
-//=============================================================================
-static
-PCPROPERTY_ITEM PropertiesCellularWaveFilter[] =
-{
- {
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_PROPOSEDATAFORMAT,
- KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_WaveFilter
- },
- {
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_PROPOSEDATAFORMAT2,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_WaveFilter
- },
- {
- &KSPROPSETID_TelephonyControl,
- KSPROPERTY_TELEPHONY_PROVIDERID,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_CellularWaveFilter
- },
- {
- &KSPROPSETID_TelephonyControl,
- KSPROPERTY_TELEPHONY_CALLINFO,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_CellularWaveFilter
- },
- {
- &KSPROPSETID_TelephonyControl,
- KSPROPERTY_TELEPHONY_CALLCONTROL,
- KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_CellularWaveFilter
- },
- {
- &KSPROPSETID_TelephonyControl,
- KSPROPERTY_TELEPHONY_PROVIDERCHANGE,
- KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_CellularWaveFilter
- },
- {
- &KSPROPSETID_TelephonyControl,
- KSPROPERTY_TELEPHONY_CALLHOLD,
- KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_CellularWaveFilter
- },
- {
- &KSPROPSETID_TelephonyControl,
- KSPROPERTY_TELEPHONY_MUTE_TX,
- KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_CellularWaveFilter
- },
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationCellularWaveFilter, PropertiesCellularWaveFilter);
-
-//=============================================================================
-static
-PCFILTER_DESCRIPTOR CellularWaveMiniportFilterDescriptor =
-{
- 0, // Version
- &AutomationCellularWaveFilter, // AutomationTable
- sizeof(PCPIN_DESCRIPTOR), // PinSize
- SIZEOF_ARRAY(CellularWaveMiniportPins), // PinCount
- CellularWaveMiniportPins, // Pins
- sizeof(PCNODE_DESCRIPTOR), // NodeSize
- 0, // NodeCount
- NULL, // Nodes
- SIZEOF_ARRAY(CellularWaveMiniportConnections), // ConnectionCount
- CellularWaveMiniportConnections, // Connections
- 0, // CategoryCount
- NULL // Categories - use defaults (audio, render, capture)
-};
-
-#endif // _SYSVAD_CELLULARWAVTABLE_H_
-
diff --git a/audio/sysvad/PhoneAudioSample/FMTopTable.h b/audio/sysvad/PhoneAudioSample/FMTopTable.h
deleted file mode 100644
index ae8ddf9e..00000000
--- a/audio/sysvad/PhoneAudioSample/FMTopTable.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- fmtoptable.h
-
-Abstract:
-
- Declaration of topology tables for the fm endpoint.
-
---*/
-
-#ifndef _SYSVAD_FMTOPTABLE_H_
-#define _SYSVAD_FMTOPTABLE_H_
-
-// {344EC7D7-F209-4FC4-B6C1-B324E8309E8D}
-DEFINE_GUID(FMRX_CUSTOM_NAME,
- 0x344ec7d7, 0xf209, 0x4fc4, 0xb6, 0xc1, 0xb3, 0x24, 0xe8, 0x30, 0x9e, 0x8d);
-
-//=============================================================================
-static
-KSDATARANGE FmTopoPinDataRangesBridge[] =
-{
- {
- sizeof(KSDATARANGE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
- }
-};
-
-//=============================================================================
-static
-PKSDATARANGE FmTopoPinDataRangePointersBridge[] =
-{
- &FmTopoPinDataRangesBridge[0]
-};
-
-//=============================================================================
-static
-PCPIN_DESCRIPTOR FmTopoMiniportPins[] =
-{
- // KSPIN_TOPO_FMRX
- {
- 0,
- 0,
- 0, // InstanceCount
- NULL, // AutomationTable
- { // KsPinDescriptor
- 0, // InterfacesCount
- NULL, // Interfaces
- 0, // MediumsCount
- NULL, // Mediums
- SIZEOF_ARRAY(FmTopoPinDataRangePointersBridge), // DataRangesCount
- FmTopoPinDataRangePointersBridge, // DataRanges
- KSPIN_DATAFLOW_IN, // DataFlow
- KSPIN_COMMUNICATION_NONE, // Communication
- &KSNODETYPE_FM_RX, // Category
- &FMRX_CUSTOM_NAME, // Name
- 0 // Reserved
- }
- },
- // KSPIN_TOPO_FMRX_BRIDGE
- {
- 0,
- 0,
- 0, // InstanceCount
- NULL, // AutomationTable
- { // KsPinDescriptor
- 0, // InterfacesCount
- NULL, // Interfaces
- 0, // MediumsCount
- NULL, // Mediums
- SIZEOF_ARRAY(FmTopoPinDataRangePointersBridge), // DataRangesCount
- FmTopoPinDataRangePointersBridge, // DataRanges
- KSPIN_DATAFLOW_OUT, // DataFlow
- KSPIN_COMMUNICATION_NONE, // Communication
- &KSCATEGORY_AUDIO, // Category
- NULL, // Name
- 0 // Reserved
- }
- },
-};
-
-//=============================================================================
-static
-KSJACK_DESCRIPTION FmRxJackDesc =
-{
- KSAUDIO_SPEAKER_STEREO,
- 0x0000, // no color
- eConnTypeOtherAnalog,
- eGeoLocNotApplicable,
- eGenLocInternal,
- ePortConnUnknown,
- FALSE
-};
-
-// Only return a KSJACK_DESCRIPTION for the physical bridge pin.
-static
-PKSJACK_DESCRIPTION FmJackDescriptions[] =
-{
- &FmRxJackDesc,
- NULL,
-};
-
-//=============================================================================
-static
-PCCONNECTION_DESCRIPTOR FmTopoMiniportConnections[] =
-{
- // FromNode, FromPin, ToNode, ToPin
- { PCFILTER_NODE, KSPIN_TOPO_FMRX, PCFILTER_NODE, KSPIN_TOPO_FMRX_BRIDGE},
-};
-
-
-//=============================================================================
-static
-PCPROPERTY_ITEM PropertiesFmTopoFilter[] =
-{
- {
- &KSPROPSETID_Jack,
- KSPROPERTY_JACK_DESCRIPTION,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_FmRxTopoFilter
- },
- {
- &KSPROPSETID_Jack,
- KSPROPERTY_JACK_DESCRIPTION2,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_FmRxTopoFilter
- },
- {
- &KSPROPSETID_FMRXTopology,
- KSPROPERTY_FMRX_ENDPOINTID,
- KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_FmRxTopoFilter
- },
- {
- &KSPROPSETID_FMRXTopology,
- KSPROPERTY_FMRX_VOLUME,
- KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_FmRxTopoFilter
- },
- {
- &KSPROPSETID_FMRXTopology,
- KSPROPERTY_FMRX_ANTENNAENDPOINTID,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_FmRxTopoFilter
- },
-};
-
-NTSTATUS CFmMiniportWaveRT_EventHandler_JackState
-(
- _In_ PPCEVENT_REQUEST EventRequest
-);
-
-static PCEVENT_ITEM FmRxJackInfoChangeEvent[] =
-{
- {
- &KSEVENTSETID_PinCapsChange, // Something changed
- KSEVENT_PINCAPS_JACKINFOCHANGE, // Jack Info Changes
- KSEVENT_TYPE_ENABLE | KSEVENT_TYPE_BASICSUPPORT,
- CFmMiniportWaveRT_EventHandler_JackState
- }
-};
-
-/*****************************************************************************
- * PropertiesTopologyFilter
- *****************************************************************************
- * Automation table for jack descripton/detection.
- */
-DEFINE_PCAUTOMATION_TABLE_PROP_EVENT(AutomationFmTopoFilter, PropertiesFmTopoFilter, FmRxJackInfoChangeEvent);
-
-
-//=============================================================================
-static
-PCFILTER_DESCRIPTOR FmTopoMiniportFilterDescriptor =
-{
- 0, // Version
- &AutomationFmTopoFilter, // AutomationTable
- sizeof(PCPIN_DESCRIPTOR), // PinSize
- SIZEOF_ARRAY(FmTopoMiniportPins), // PinCount
- FmTopoMiniportPins, // Pins
- sizeof(PCNODE_DESCRIPTOR), // NodeSize
- 0, // NodeCount
- NULL, // Nodes
- SIZEOF_ARRAY(FmTopoMiniportConnections), // ConnectionCount
- FmTopoMiniportConnections, // Connections
- 0, // CategoryCount
- NULL // Categories
-};
-
-#endif // _SYSVAD_FMTOPTABLE_H_
-
-
diff --git a/audio/sysvad/PhoneAudioSample/FMTopo.cpp b/audio/sysvad/PhoneAudioSample/FMTopo.cpp
deleted file mode 100644
index 9c43168f..00000000
--- a/audio/sysvad/PhoneAudioSample/FMTopo.cpp
+++ /dev/null
@@ -1,985 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- fmtopo.cpp
-
-Abstract:
-
- Implementation of topology miniport for the fm endpoint.
-
---*/
-
-#pragma warning (disable : 4127)
-
-#include <sysvad.h>
-#include "simple.h"
-#include "mintopo.h"
-#include "fmtopo.h"
-#include "fmtoptable.h"
-#include <ntstrsafe.h>
-
-
-#pragma code_seg("PAGE")
-
-// Table of valid render endpoints for FM
-KSTOPOLOGY_ENDPOINTID g_EndpointList[] =
-{
- { SPEAKER_TOPONAME, KSPIN_TOPO_LINEOUT_DEST },
- { SPEAKER_HEADSET_TOPONAME, KSPIN_TOPO_LINEOUT_DEST },
- { HOSTRENDER_TOPONAME, HOSTRENDER_PIN }
-};
-
-KSTOPOLOGY_ENDPOINTID g_AntennaEndpoint =
-{
- SPEAKER_HEADSET_TOPONAME, KSPIN_TOPO_LINEOUT_DEST
-};
-
-//=============================================================================
-NTSTATUS
-CreateFmMiniportTopology
-(
- _Out_ PUNKNOWN * Unknown,
- _In_ REFCLSID,
- _In_opt_ PUNKNOWN UnknownOuter,
- _When_((PoolType & NonPagedPoolMustSucceed) != 0,
- __drv_reportError("Must succeed pool allocations are forbidden. "
- "Allocation failures cause a system crash"))
- _In_ POOL_TYPE PoolType,
- _In_ PUNKNOWN UnknownAdapter,
- _In_opt_ PVOID DeviceContext,
- _In_ PENDPOINT_MINIPAIR MiniportPair
-)
-/*++
-
-Routine Description:
-
- Creates a new topology miniport.
-
-Arguments:
-
- Unknown -
-
- RefclsId -
-
- UnknownOuter -
-
- PoolType -
-
- UnknownAdapter -
-
- DeviceContext -
-
- MiniportPair -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(Unknown);
- ASSERT(MiniportPair);
-
- UNREFERENCED_PARAMETER(UnknownAdapter);
- UNREFERENCED_PARAMETER(DeviceContext);
-
- CFmMiniportTopology *obj =
- new (PoolType, MINWAVERT_POOLTAG)
- CFmMiniportTopology( UnknownOuter,
- MiniportPair->TopoDescriptor,
- MiniportPair->DeviceMaxChannels);
- if (NULL == obj)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- obj->AddRef();
- *Unknown = reinterpret_cast<IUnknown*>(obj);
-
- return STATUS_SUCCESS;
-} // CreateFmMiniportTopology
-
-CFmMiniportTopology::CFmMiniportTopology
-(
- _In_opt_ PUNKNOWN UnknownOuter,
- _In_ PCFILTER_DESCRIPTOR *FilterDesc,
- _In_ USHORT DeviceMaxChannels
-)
-: CUnknown(UnknownOuter),
- CMiniportTopologySYSVAD(FilterDesc, DeviceMaxChannels),
- m_FmRxVolume(FMRX_VOLUME_MAXIMUM)
-{
- PAGED_CODE();
-
- memcpy(&m_FmRxTargetEndpoint, &g_EndpointList[0], sizeof(m_FmRxTargetEndpoint));
-}
-
-
-//=============================================================================
-CFmMiniportTopology::~CFmMiniportTopology
-(
- void
-)
-/*++
-
-Routine Description:
-
- Topology miniport destructor
-
-Arguments:
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- DPF_ENTER(("[CFmMiniportTopology::~CFmMiniportTopology]"));
-} // ~CFmMiniportTopology
-
-//=============================================================================
-NTSTATUS
-CFmMiniportTopology::DataRangeIntersection
-(
- _In_ ULONG PinId,
- _In_ PKSDATARANGE ClientDataRange,
- _In_ PKSDATARANGE MyDataRange,
- _In_ ULONG OutputBufferLength,
- _Out_writes_bytes_to_opt_(OutputBufferLength, *ResultantFormatLength)
- PVOID ResultantFormat OPTIONAL,
- _Out_ PULONG ResultantFormatLength
-)
-/*++
-
-Routine Description:
-
- The DataRangeIntersection function determines the highest quality
- intersection of two data ranges.
-
-Arguments:
-
- PinId - Pin for which data intersection is being determined.
-
- ClientDataRange - Pointer to KSDATARANGE structure which contains the data range
- submitted by client in the data range intersection property
- request.
-
- MyDataRange - Pin's data range to be compared with client's data range.
-
- OutputBufferLength - Size of the buffer pointed to by the resultant format
- parameter.
-
- ResultantFormat - Pointer to value where the resultant format should be
- returned.
-
- ResultantFormatLength - Actual length of the resultant format that is placed
- at ResultantFormat. This should be less than or equal
- to OutputBufferLength.
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- return
- CMiniportTopologySYSVAD::DataRangeIntersection
- (
- PinId,
- ClientDataRange,
- MyDataRange,
- OutputBufferLength,
- ResultantFormat,
- ResultantFormatLength
- );
-} // DataRangeIntersection
-
-//=============================================================================
-STDMETHODIMP
-CFmMiniportTopology::GetDescription
-(
- _Out_ PPCFILTER_DESCRIPTOR * OutFilterDescriptor
-)
-/*++
-
-Routine Description:
-
- The GetDescription function gets a pointer to a filter description.
- It provides a location to deposit a pointer in miniport's description
- structure. This is the placeholder for the FromNode or ToNode fields in
- connections which describe connections to the filter's pins.
-
-Arguments:
-
- OutFilterDescriptor - Pointer to the filter description.
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(OutFilterDescriptor);
-
- return CMiniportTopologySYSVAD::GetDescription(OutFilterDescriptor);
-} // GetDescription
-
-//=============================================================================
-STDMETHODIMP
-CFmMiniportTopology::Init
-(
- _In_ PUNKNOWN UnknownAdapter,
- _In_ PRESOURCELIST ResourceList,
- _In_ PPORTTOPOLOGY Port_
-)
-/*++
-
-Routine Description:
-
- The Init function initializes the miniport. Callers of this function
- should run at IRQL PASSIVE_LEVEL
-
-Arguments:
-
- UnknownAdapter - A pointer to the Iuknown interface of the adapter object.
-
- ResourceList - Pointer to the resource list to be supplied to the miniport
- during initialization. The port driver is free to examine the
- contents of the ResourceList. The port driver will not be
- modify the ResourceList contents.
-
- Port - Pointer to the topology port object that is linked with this miniport.
-
-Return Value:
-
- NT status code.
-
---*/
-{
- UNREFERENCED_PARAMETER(ResourceList);
-
- PAGED_CODE();
-
- ASSERT(UnknownAdapter);
- ASSERT(Port_);
-
- DPF_ENTER(("[CFmMiniportTopology::Init]"));
-
- NTSTATUS ntStatus;
-
- ntStatus =
- CMiniportTopologySYSVAD::Init
- (
- UnknownAdapter,
- Port_
- );
-
- return ntStatus;
-} // Init
-
-//=============================================================================
-STDMETHODIMP
-CFmMiniportTopology::NonDelegatingQueryInterface
-(
- _In_ REFIID Interface,
- _COM_Outptr_ PVOID * Object
-)
-/*++
-
-Routine Description:
-
- QueryInterface for MiniportTopology
-
-Arguments:
-
- Interface - GUID of the interface
-
- Object - interface object to be returned.
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(Object);
-
- if (IsEqualGUIDAligned(Interface, IID_IUnknown))
- {
- *Object = PVOID(PUNKNOWN(this));
- }
- else if (IsEqualGUIDAligned(Interface, IID_IMiniport))
- {
- *Object = PVOID(PMINIPORT(this));
- }
- else if (IsEqualGUIDAligned(Interface, IID_IMiniportTopology))
- {
- *Object = PVOID(PMINIPORTTOPOLOGY(this));
- }
- else if (IsEqualGUIDAligned(Interface, IID_IFmTopology))
- {
- *Object = PVOID(PFMTOPOLOGY(this));
- }
- else
- {
- *Object = NULL;
- }
-
- if (*Object)
- {
- // We reference the interface for the caller.
- PUNKNOWN(*Object)->AddRef();
- return(STATUS_SUCCESS);
- }
-
- return(STATUS_INVALID_PARAMETER);
-} // NonDelegatingQueryInterface
-
-//=============================================================================
-NTSTATUS
-CFmMiniportTopology::PropertyHandlerJackDescription
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION )
-
-Arguments:
-
- PropertyRequest
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandlerJackDescription]"));
-
- ULONG cJackDescriptions = ARRAYSIZE(FmJackDescriptions);
- PKSJACK_DESCRIPTION * JackDescriptions = FmJackDescriptions;
-
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- ULONG nPinId = (ULONG)-1;
-
- if (PropertyRequest->InstanceSize >= sizeof(ULONG))
- {
- nPinId = *(PULONG(PropertyRequest->Instance));
-
- if ((nPinId < cJackDescriptions) && (JackDescriptions[nPinId] != NULL))
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ntStatus =
- PropertyHandler_BasicSupport
- (
- PropertyRequest,
- KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
- VT_ILLEGAL
- );
- }
- else
- {
- ULONG cbNeeded = sizeof(KSMULTIPLE_ITEM) + sizeof(KSJACK_DESCRIPTION);
-
- if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = cbNeeded;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else if (PropertyRequest->ValueSize < cbNeeded)
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- PKSMULTIPLE_ITEM pMI = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
- PKSJACK_DESCRIPTION pDesc = (PKSJACK_DESCRIPTION)(pMI+1);
-
- pMI->Size = cbNeeded;
- pMI->Count = 1;
-
- RtlCopyMemory(pDesc, JackDescriptions[nPinId], sizeof(KSJACK_DESCRIPTION));
- ntStatus = STATUS_SUCCESS;
- }
- }
- }
- }
- }
-
- return ntStatus;
-}
-
-//=============================================================================
-NTSTATUS
-CFmMiniportTopology::PropertyHandlerJackDescription2
-(
-_In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
-Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION2 )
-
-Arguments:
-
-PropertyRequest -
-
-Return Value:
-
-NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandlerJackDescription2]"));
-
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- ULONG nPinId = (ULONG)-1;
-
- ULONG cJackDescriptions = ARRAYSIZE(FmJackDescriptions);
- PKSJACK_DESCRIPTION * JackDescriptions = FmJackDescriptions;
-
- if (PropertyRequest->InstanceSize >= sizeof(ULONG))
- {
- nPinId = *(PULONG(PropertyRequest->Instance));
-
- if ((nPinId < cJackDescriptions) && (JackDescriptions[nPinId] != NULL))
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ntStatus =
- PropertyHandler_BasicSupport
- (
- PropertyRequest,
- KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
- VT_ILLEGAL
- );
- }
- else
- {
- ULONG cbNeeded = sizeof(KSMULTIPLE_ITEM)+sizeof(KSJACK_DESCRIPTION2);
-
- if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = cbNeeded;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else if (PropertyRequest->ValueSize < cbNeeded)
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- PKSMULTIPLE_ITEM pMI = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
- PKSJACK_DESCRIPTION2 pDesc = (PKSJACK_DESCRIPTION2)(pMI + 1);
-
- pMI->Size = cbNeeded;
- pMI->Count = 1;
-
- RtlZeroMemory(pDesc, sizeof(KSJACK_DESCRIPTION2));
-
- //
- // Specifies the lower 16 bits of the DWORD parameter. This parameter indicates whether
- // the jack is currently active, streaming, idle, or hardware not ready.
- //
- pDesc->DeviceStateInfo = 0;
-
- //
- // From MSDN:
- // "If an audio device lacks jack presence detection, the IsConnected member of
- // the KSJACK_DESCRIPTION structure must always be set to TRUE. To remove the
- // ambiguity that results from this dual meaning of the TRUE value for IsConnected,
- // a client application can call IKsJackDescription2::GetJackDescription2 to read
- // the JackCapabilities flag of the KSJACK_DESCRIPTION2 structure. If this flag has
- // the JACKDESC2_PRESENCE_DETECT_CAPABILITY bit set, it indicates that the endpoint
- // does in fact support jack presence detection. In that case, the return value of
- // the IsConnected member can be interpreted to accurately reflect the insertion status
- // of the jack."
- //
- // Bit definitions:
- // 0x00000001 - JACKDESC2_PRESENCE_DETECT_CAPABILITY
- // 0x00000002 - JACKDESC2_DYNAMIC_FORMAT_CHANGE_CAPABILITY
- //
- pDesc->JackCapabilities = JACKDESC2_PRESENCE_DETECT_CAPABILITY;
-
- ntStatus = STATUS_SUCCESS;
- }
- }
- }
- }
- }
-
- return ntStatus;
-}
-
-//=============================================================================
-NTSTATUS
-CFmMiniportTopology::PropertyHandlerFmRxEndpointId
-(
-_In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
-Handles ( KSPROPSETID_FMRXTopology, KSPROPERTY_FMRX_ENDPOINTID )
-
-Arguments:
-
-PropertyRequest
-
-Return Value:
-
-NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandlerFmRxEndpointId]"));
-
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
-
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- ULONG ulExpectedSize = (sizeof(KSPROPERTY_DESCRIPTION)+sizeof(KSPROPERTY_MEMBERSHEADER)+sizeof(g_EndpointList));
-
- if (PropertyRequest->ValueSize >= sizeof(KSPROPERTY_DESCRIPTION))
- {
- // if return buffer can hold a KSPROPERTY_DESCRIPTION, return it
- //
- PKSPROPERTY_DESCRIPTION PropDesc =
- PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
-
- PropDesc->AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_GET;
- PropDesc->DescriptionSize = ulExpectedSize;
- PropDesc->PropTypeSet.Set = KSPROPSETID_FMRXTopology;
- PropDesc->PropTypeSet.Id = KSPROPERTY_FMRX_ENDPOINTID;
- PropDesc->PropTypeSet.Flags = 0;
- PropDesc->MembersListCount = 1;
- PropDesc->Reserved = 0;
-
- // buffer is big enough to hold the full data, add that
- if (PropertyRequest->ValueSize >= ulExpectedSize)
- {
- PKSPROPERTY_MEMBERSHEADER MembersHeader =
- PKSPROPERTY_MEMBERSHEADER(PropDesc + 1);
-
- MembersHeader->MembersFlags = KSPROPERTY_MEMBER_VALUES;
- MembersHeader->MembersSize = sizeof(KSTOPOLOGY_ENDPOINTID);
- MembersHeader->MembersCount = SIZEOF_ARRAY(g_EndpointList);
- MembersHeader->Flags = 0;
-
- memcpy(MembersHeader + 1, g_EndpointList, sizeof(g_EndpointList));
-
- // tell them how much space we really used, which controls how much data is copied into the user buffer.
- PropertyRequest->ValueSize = ulExpectedSize;
- }
- else
- {
- // tell them how much space we really used, which controls how much data is copied into the user buffer.
- PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION);
- }
-
- ntStatus = STATUS_SUCCESS;
- }
- else if (PropertyRequest->ValueSize >= sizeof(ULONG))
- {
- // if return buffer can hold a ULONG, return the access flags.
- *(PULONG(PropertyRequest->Value)) = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_GET;
- PropertyRequest->ValueSize = sizeof(ULONG);
- ntStatus = STATUS_SUCCESS;
- }
- else if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = ulExpectedSize;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- }
- else
- {
- ntStatus =
- ValidatePropertyParams
- (
- PropertyRequest,
- sizeof(KSTOPOLOGY_ENDPOINTID),
- 0
- );
-
- if (NT_SUCCESS(ntStatus))
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- PKSTOPOLOGY_ENDPOINTID EndpointId = static_cast<PKSTOPOLOGY_ENDPOINTID>(PropertyRequest->Value);
-
- memcpy(EndpointId, &m_FmRxTargetEndpoint, sizeof(m_FmRxTargetEndpoint));
-
- ntStatus = STATUS_SUCCESS;
- }
- else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
- {
- PKSTOPOLOGY_ENDPOINTID EndpointId = static_cast<PKSTOPOLOGY_ENDPOINTID>(PropertyRequest->Value);
-
- ntStatus = STATUS_INVALID_PARAMETER;
- for (int i = 0; i < SIZEOF_ARRAY(g_EndpointList); i++)
- {
- if (g_EndpointList[i].PinId == EndpointId->PinId &&
- 0 == _wcsnicmp(g_EndpointList[i].TopologyName, EndpointId->TopologyName, MAX_PATH))
- {
- memcpy(&m_FmRxTargetEndpoint, EndpointId, sizeof(m_FmRxTargetEndpoint));
-
- if (HOSTRENDER_PIN == EndpointId->PinId &&
- 0 == _wcsnicmp(HOSTRENDER_TOPONAME, EndpointId->TopologyName, MAX_PATH))
- {
- // This is an indication that FM audio is being routed through OS (For example, user plugs in
- // USB headset for FM audio) and driver must stop rendering FM audio to any physical audio endpoint.
- }
- else
- {
- // Route FM audio to this new endpoint.
- }
- ntStatus = STATUS_SUCCESS;
- break;
- }
- }
- }
- else
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- }
-
- return ntStatus;
-}
-
-//=============================================================================
-NTSTATUS
-CFmMiniportTopology::PropertyHandlerFmRxVolume
-(
-_In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
-Handles ( KSPROPSETID_FMRXTopology, KSPROPERTY_FMRX_VOLUME )
-
-Arguments:
-
-PropertyRequest
-
-Return Value:
-
-NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandlerFmRxVolume]"));
-
- UNREFERENCED_PARAMETER(PropertyRequest);
-
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
-
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ntStatus =
- PropertyHandler_BasicSupportVolume
- (
- PropertyRequest,
- 1 // FM audio technically supports Stereo, but we only support a single volume
- );
-
- ULONG cbFullProperty =
- sizeof(KSPROPERTY_DESCRIPTION)+
- sizeof(KSPROPERTY_MEMBERSHEADER)+
- sizeof(KSPROPERTY_STEPPING_LONG);
-
- if (NT_SUCCESS(ntStatus) && PropertyRequest->ValueSize >= cbFullProperty)
- {
- // Access proper values
- PKSPROPERTY_DESCRIPTION PropDesc =
- PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
- PKSPROPERTY_MEMBERSHEADER Members =
- PKSPROPERTY_MEMBERSHEADER(PropDesc + 1);
- PKSPROPERTY_STEPPING_LONG Range =
- PKSPROPERTY_STEPPING_LONG(Members + 1);
-
- Members->Flags = 0;
-
- Range->Bounds.SignedMaximum = FMRX_VOLUME_MAXIMUM;
- Range->Bounds.SignedMinimum = FMRX_VOLUME_MINIMUM;
- Range->SteppingDelta = FMRX_VOLUME_STEPPING;
- }
- }
- else
- {
- ntStatus =
- ValidatePropertyParams
- (
- PropertyRequest,
- sizeof(LONG), // volume value is a LONG
- 0 // No support for channel since this is a property
- // on the topo filter, not a volume node.
- );
-
-
- if (NT_SUCCESS(ntStatus))
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- LONG* volume = (LONG*)PropertyRequest->Value;
- // Return current FM volume
- *volume = m_FmRxVolume;
- ntStatus = STATUS_SUCCESS;
- }
- else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
- {
- LONG* volume = (LONG*)PropertyRequest->Value;
-
- LONG normalizedVolume =
- VALUE_NORMALIZE_IN_RANGE_EX
- (
- *volume,
- FMRX_VOLUME_MINIMUM,
- FMRX_VOLUME_MAXIMUM,
- FMRX_VOLUME_STEPPING
- );
- if (normalizedVolume == *volume)
- {
- m_FmRxVolume = *volume;
- ntStatus = STATUS_SUCCESS;
- }
- else
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- else
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- }
-
- return ntStatus;
-}
-
-//=============================================================================
-NTSTATUS
-CFmMiniportTopology::PropertyHandlerFmRxAntennaEndpointId
-(
-_In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
-Handles ( KSPROPSETID_FMRXTopology, KSPROPERTY_FMRX_ANTENNAENDPOINTID )
-
-Arguments:
-
-PropertyRequest
-
-Return Value:
-
-NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandlerFmRxAntennaEndpoint]"));
-
- UNREFERENCED_PARAMETER(PropertyRequest);
-
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
-
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ULONG flags = PropertyRequest->PropertyItem->Flags;
- ntStatus = PropertyHandler_BasicSupport(PropertyRequest, flags, VT_ILLEGAL);
- }
- else
- {
- ntStatus =
- ValidatePropertyParams
- (
- PropertyRequest,
- sizeof(KSTOPOLOGY_ENDPOINTID),
- 0
- );
-
-
- if (NT_SUCCESS(ntStatus))
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- PKSTOPOLOGY_ENDPOINTID pEndpointId = (PKSTOPOLOGY_ENDPOINTID)PropertyRequest->Value;
- memcpy(pEndpointId, &g_AntennaEndpoint, sizeof(*pEndpointId));
- ntStatus = STATUS_SUCCESS;
- }
- else
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- }
-
- return ntStatus;
-}
-
-//=============================================================================
-NTSTATUS
-PropertyHandler_FmRxTopoFilter
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Redirects property request to miniport object
-
-Arguments:
-
- PropertyRequest -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandler_FmRxTopoFilter]"));
-
- // PropertryRequest structure is filled by portcls.
- // MajorTarget is a pointer to miniport object for miniports.
- //
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- PCFmMiniportTopology pMiniport = (PCFmMiniportTopology)PropertyRequest->MajorTarget;
-
- if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Jack))
- {
- if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION)
- {
- ntStatus = pMiniport->PropertyHandlerJackDescription(PropertyRequest);
- }
- else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION2)
- {
- ntStatus = pMiniport->PropertyHandlerJackDescription2(PropertyRequest);
- }
- }
- else if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_FMRXTopology))
- {
- if (PropertyRequest->PropertyItem->Id == KSPROPERTY_FMRX_ENDPOINTID)
- {
- ntStatus = pMiniport->PropertyHandlerFmRxEndpointId(PropertyRequest);
- }
- else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_FMRX_VOLUME)
- {
- ntStatus = pMiniport->PropertyHandlerFmRxVolume(PropertyRequest);
- }
- else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_FMRX_ANTENNAENDPOINTID)
- {
- ntStatus = pMiniport->PropertyHandlerFmRxAntennaEndpointId(PropertyRequest);
- }
- }
-
- return ntStatus;
-} // PropertyHandler_FmRxTopoFilter
-
-#pragma code_seg("PAGE")
-STDMETHODIMP_(NTSTATUS)
-CFmMiniportTopology::UpdateTopologyJackState
-(
- _In_ BOOL NewState
-)
-{
- PAGED_CODE ();
-
- FmRxJackDesc.IsConnected = NewState;
-
- // we have multiple pins which share the same jack state,
- // notify for every pin using that jack state
- GenerateEventList(
- (GUID*)&KSEVENTSETID_PinCapsChange, // event set. NULL is a wild card for all events.
- KSEVENT_PINCAPS_JACKINFOCHANGE, // event ID.
- TRUE, // use pid ID.
- KSPIN_TOPO_FMRX, // pin ID.
- FALSE, // do not use node ID.
- ULONG(-1)); // node ID, not used.
-
- return STATUS_SUCCESS;
-}
-
-#pragma code_seg()
-NTSTATUS CFmMiniportWaveRT_EventHandler_JackState
-(
- _In_ PPCEVENT_REQUEST EventRequest
-)
-{
- CFmMiniportTopology* miniport = reinterpret_cast<CFmMiniportTopology*>(EventRequest->MajorTarget);
- return miniport->EventHandler_JackState(EventRequest);
-}
-
-NTSTATUS CFmMiniportTopology::EventHandler_JackState
-(
- _In_ PPCEVENT_REQUEST EventRequest
-)
-{
- if (EventRequest->Verb == PCEVENT_VERB_ADD)
- {
- m_PortEvents->AddEventToEventList(EventRequest->EventEntry);
- }
-
- return STATUS_SUCCESS;
-}
-
-
diff --git a/audio/sysvad/PhoneAudioSample/FMTopo.h b/audio/sysvad/PhoneAudioSample/FMTopo.h
deleted file mode 100644
index ae279bf1..00000000
--- a/audio/sysvad/PhoneAudioSample/FMTopo.h
+++ /dev/null
@@ -1,152 +0,0 @@
-
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- FMtopo.h
-
-Abstract:
-
- Declaration of topology miniport for the fm endpoint.
-
---*/
-
-#ifndef _SYSVAD_FMTOPO_H_
-#define _SYSVAD_FMTOPO_H_
-
-#include "basetopo.h"
-
-// make sure all of these names matches with KSNAME_* in the inf's [Strings] section
-#define SPEAKER_TOPONAME L"TopologySpeaker"
-#define SPEAKER_HEADSET_TOPONAME L"TopologySpeakerHeadset"
-
-// Special routing endpoint
-#define HOSTRENDER_TOPONAME L"HostRender"
-#define HOSTRENDER_PIN 0
-
-// FM Volume Stepping information
-#define FMRX_VOLUME_MAXIMUM 0 // 0 dB
-#define FMRX_VOLUME_MINIMUM (-96 * 0x10000) // -96 dB
-#define FMRX_VOLUME_STEPPING (0x8000) // 0.5 dB steps
-
-
-//=============================================================================
-// Defines
-//=============================================================================
-// {949F42F1-A5F5-4FBD-B4BB-C543ACC24AE0}
-DEFINE_GUID(IID_IFmTopology,
- 0x949f42f1, 0xa5f5, 0x4fbd, 0xb4, 0xbb, 0xc5, 0x43, 0xac, 0xc2, 0x4a, 0xe0);
-
-
-//=============================================================================
-// Interfaces
-//=============================================================================
-
-///////////////////////////////////////////////////////////////////////////////
-// IFmTopology
-//
-DECLARE_INTERFACE_(IFmTopology, IMiniportTopology)
-{
- STDMETHOD_(NTSTATUS, UpdateTopologyJackState)
- (
- THIS_
- _In_ BOOL NewState
- ) PURE;
-};
-
-typedef IFmTopology *PFMTOPOLOGY;
-
-//=============================================================================
-// Classes
-//=============================================================================
-
-///////////////////////////////////////////////////////////////////////////////
-// CFmMiniportTopology
-//
-
-class CFmMiniportTopology :
- public CMiniportTopologySYSVAD,
- public IFmTopology,
- public CUnknown
-{
- private:
- KSTOPOLOGY_ENDPOINTID m_FmRxTargetEndpoint;
- KSTOPOLOGY_ENDPOINTID m_FmRxAntennaEndpoint;
- ULONG m_FmRxVolume;
-
- public:
- DECLARE_STD_UNKNOWN();
- CFmMiniportTopology
- (
- _In_opt_ PUNKNOWN UnknownOuter,
- _In_ PCFILTER_DESCRIPTOR *FilterDesc,
- _In_ USHORT DeviceMaxChannels
- );
-
- ~CFmMiniportTopology();
-
- IMP_IMiniportTopology;
-
- NTSTATUS PropertyHandlerJackSinkInfo
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
- NTSTATUS PropertyHandlerJackDescription
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
- NTSTATUS PropertyHandlerJackDescription2
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
- NTSTATUS PropertyHandlerFmRxEndpointId
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
- NTSTATUS PropertyHandlerFmRxVolume
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
- NTSTATUS PropertyHandlerFmRxAntennaEndpointId
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
- NTSTATUS EventHandler_JackState
- (
- _In_ PPCEVENT_REQUEST _pEventRequest
- );
-
- STDMETHODIMP_(NTSTATUS) UpdateTopologyJackState
- (
- _In_ BOOL NewState
- );
-};
-
-typedef CFmMiniportTopology *PCFmMiniportTopology;
-
-NTSTATUS
-CreateFmMiniportTopology(
- _Out_ PUNKNOWN * Unknown,
- _In_ REFCLSID,
- _In_opt_ PUNKNOWN UnknownOuter,
- _When_((PoolType & NonPagedPoolMustSucceed) != 0,
- __drv_reportError("Must succeed pool allocations are forbidden. "
- "Allocation failures cause a system crash"))
- _In_ POOL_TYPE PoolType,
- _In_ PUNKNOWN UnknownAdapter,
- _In_opt_ PVOID DeviceContext,
- _In_ PENDPOINT_MINIPAIR MiniportPair
- );
-
-NTSTATUS PropertyHandler_FmRxTopoFilter(_In_ PPCPROPERTY_REQUEST PropertyRequest);
-
-#endif // _SYSVAD_FMTOPO_H_
-
diff --git a/audio/sysvad/PhoneAudioSample/FMWave.cpp b/audio/sysvad/PhoneAudioSample/FMWave.cpp
deleted file mode 100644
index 4d571f57..00000000
--- a/audio/sysvad/PhoneAudioSample/FMWave.cpp
+++ /dev/null
@@ -1,389 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- fmwave.cpp
-
-Abstract:
-
- Implementation of wavert miniport for fm
-
---*/
-
-#pragma warning (disable : 4127)
-
-#include <sysvad.h>
-#include "simple.h"
-#include "FmWave.h"
-#include "FmTopo.h"
-#include "FmToptable.h"
-
-//=============================================================================
-// CFmMiniportWaveRT
-//=============================================================================
-
-//=============================================================================
-#pragma code_seg("PAGE")
-NTSTATUS
-CreateFmMiniportWaveRT
-(
- _Out_ PUNKNOWN * Unknown,
- _In_ REFCLSID,
- _In_opt_ PUNKNOWN UnknownOuter,
- _When_((PoolType & NonPagedPoolMustSucceed) != 0,
- __drv_reportError("Must succeed pool allocations are forbidden. "
- "Allocation failures cause a system crash"))
- _In_ POOL_TYPE PoolType,
- _In_ PUNKNOWN UnknownAdapter,
- _In_opt_ PVOID DeviceContext,
- _In_ PENDPOINT_MINIPAIR MiniportPair
-)
-/*++
-
-Routine Description:
-
- Create the wavert miniport.
-
-Arguments:
-
- Unknown -
-
- RefClsId -
-
- UnknownOuter -
-
- PoolType -
-
- UnkownAdapter -
-
- DeviceContext -
-
- MiniportPair -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- UNREFERENCED_PARAMETER(UnknownOuter);
-
- PAGED_CODE();
-
- ASSERT(Unknown);
- ASSERT(MiniportPair);
-
- CMiniportWaveRT *obj = new (PoolType, MINWAVERT_POOLTAG) CFmMiniportWaveRT
- (
- UnknownAdapter,
- MiniportPair,
- DeviceContext
- );
- if (NULL == obj)
- {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- obj->AddRef();
- *Unknown = reinterpret_cast<IUnknown*>(obj);
-
- return STATUS_SUCCESS;
-}
-
-//=============================================================================
-#pragma code_seg("PAGE")
-CFmMiniportWaveRT::~CFmMiniportWaveRT
-(
- void
-)
-/*++
-
-Routine Description:
-
- Destructor for wavert miniport
-
-Arguments:
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- DPF_ENTER(("[CFmMiniportWaveRT::~CFmMiniportWaveRT]"));
-
-} // ~CFmMiniportWaveRT
-
-
-//=============================================================================
-#pragma code_seg("PAGE")
-STDMETHODIMP
-CFmMiniportWaveRT::NonDelegatingQueryInterface
-(
- _In_ REFIID Interface,
- _COM_Outptr_ PVOID * Object
-)
-/*++
-
-Routine Description:
-
- QueryInterface for CFmMiniportWaveRT
-
-Arguments:
-
- Interface - GUID of the interface
-
- Object - interface object to be returned.
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(Object);
-
- if (IsEqualGUIDAligned(Interface, IID_IAdapterPowerManagement))
- {
- *Object = PVOID(PADAPTERPOWERMANAGEMENT(this));
- }
- else
- {
- *Object = NULL;
- }
-
- if (*Object)
- {
- // We reference the interface for the caller.
-
- PUNKNOWN(*Object)->AddRef();
- return STATUS_SUCCESS;
- }
-
- return CMiniportWaveRT::NonDelegatingQueryInterface(Interface, Object);
-}
-
-#pragma code_seg("PAGE")
-NTSTATUS
-PropertyHandler_FmRxWaveFilter
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Redirects general property request to miniport object
-
-Arguments:
-
- PropertyRequest -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- CFmMiniportWaveRT* pWaveHelper = reinterpret_cast<CFmMiniportWaveRT*>(PropertyRequest->MajorTarget);
-
- if (pWaveHelper == NULL)
- {
- return STATUS_INVALID_PARAMETER;
- }
-
- pWaveHelper->AddRef();
-
- if (pWaveHelper->m_DeviceType == eFmRxDevice &&
- IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_FMRXControl))
- {
- switch (PropertyRequest->PropertyItem->Id)
- {
- case KSPROPERTY_FMRX_STATE:
- ntStatus = pWaveHelper->PropertyHandler_FmRxState(PropertyRequest);
- break;
-
- default:
- DPF(D_TERSE, ("[PropertyHandler_FmRxWaveFilter: Invalid Device Request"));
- }
- }
- else
- {
- ntStatus = PropertyHandler_WaveFilter(PropertyRequest);
- }
-
- pWaveHelper->Release();
-
- return ntStatus;
-} // PropertyHandler_FmRxWaveFilter
-
-//=============================================================================
-#pragma code_seg("PAGE")
-NTSTATUS
-CFmMiniportWaveRT::PropertyHandler_FmRxState
-(
-_In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-{
- NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
-
- PAGED_CODE();
-
- DPF_ENTER(("[CFmMiniportWaveRT::PropertyHandler_FmRxState]"));
-
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ULONG flags = PropertyRequest->PropertyItem->Flags;
- ntStatus = PropertyHandler_BasicSupport(PropertyRequest, flags, VT_ILLEGAL);
- }
- else
- {
- ntStatus =
- ValidatePropertyParams
- (
- PropertyRequest,
- sizeof(BOOL),
- 0
- );
-
- if (NT_SUCCESS(ntStatus))
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- BOOL* fmrxState = (BOOL*)PropertyRequest->Value;
- *fmrxState = m_bFmRxState;
- ntStatus = STATUS_SUCCESS;
- }
- else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
- {
- BOOL fmrxNewState = *(BOOL*)PropertyRequest->Value;
- if (fmrxNewState == m_bFmRxState)
- {
- ntStatus = STATUS_SUCCESS;
- }
- else
- {
- // Turn on FM hardware
- m_bFmRxState = fmrxNewState;
-
- // NOTE: Set the Jack state to Active ONLY if the driver supports
- // recording FM data. If the driver doesn't support recording FM
- // data, the jack state should never be changed to Active
- ntStatus = UpdateTopologyJackState(m_bFmRxState);
-
- // When we're using FM, we need idle power management disabled.
- // passing true here enables power management, false disables.
- // when FM is enabled (true), we want to pass false do disable idle
- // power management
- m_pAdapterCommon->SetIdlePowerManagement(m_pMiniportPair, m_bFmRxState?FALSE:TRUE);
- }
- }
- else
- {
- ntStatus = STATUS_INVALID_PARAMETER;
- }
- }
- }
-
- return ntStatus;
-} // PropertyHandler_FmRxState
-
-
-
-#pragma code_seg("PAGE")
-NTSTATUS
-CFmMiniportWaveRT::UpdateTopologyJackState
-(
- _In_ BOOL NewState
-)
-{
- PAGED_CODE ();
- NTSTATUS ntStatus = STATUS_SUCCESS;
- IUnknown *pUnknown = NULL;
- IFmTopology *pFmTopology = NULL;
-
- // GetFilters returns the topology port, then topology miniport, then wave port, then wave miniport.
- // we only need the topology miniport.
- ntStatus = m_pAdapterCommon->GetFilters(m_pMiniportPair, NULL, &pUnknown, NULL, NULL);
- if (NT_SUCCESS(ntStatus))
- {
- ntStatus = pUnknown->QueryInterface(IID_IFmTopology, (PVOID *)&pFmTopology);
- if (NT_SUCCESS(ntStatus))
- {
- ntStatus = pFmTopology->UpdateTopologyJackState(NewState);
- }
- }
-
- SAFE_RELEASE(pFmTopology);
- SAFE_RELEASE(pUnknown);
-
- return STATUS_SUCCESS;
-}
-#pragma code_seg()
-
-
-//=============================================================================
-#pragma code_seg()
-STDMETHODIMP_(void)
-CFmMiniportWaveRT::PowerChangeState
-(
- _In_ POWER_STATE NewState
-)
-{
- DPF_ENTER(("[CFmMiniportWaveRT::PowerChangeState]"));
- UNREFERENCED_PARAMETER(NewState);
-
- /*
- Turn on and off fm specific hardware here, if applicable.
- */
-
-} // PowerStateChange
-
-//=============================================================================
-#pragma code_seg()
-STDMETHODIMP_(NTSTATUS)
-CFmMiniportWaveRT::QueryDeviceCapabilities
-(
- _Inout_updates_bytes_(sizeof(DEVICE_CAPABILITIES)) PDEVICE_CAPABILITIES PowerDeviceCaps
-)
-{
- UNREFERENCED_PARAMETER(PowerDeviceCaps);
-
- /*
- Unused at the miniport layer. Any device capabilities should be reported in CAdapterCommon
- */
-
- return (STATUS_SUCCESS);
-} // QueryDeviceCapabilities
-
-//=============================================================================
-#pragma code_seg()
-STDMETHODIMP_(NTSTATUS)
-CFmMiniportWaveRT::QueryPowerChangeState
-(
- _In_ POWER_STATE NewStateQuery
-)
-{
- UNREFERENCED_PARAMETER(NewStateQuery);
-
- DPF_ENTER(("[CFmMiniportWaveRT::QueryPowerChangeState]"));
-
- // if we're in a call state other than disabled, then we need the hardware turned on
- if (m_bFmRxState)
- {
- return STATUS_RESOURCE_IN_USE;
- }
-
- return STATUS_SUCCESS;
-} // QueryPowerChangeState
-
-
diff --git a/audio/sysvad/PhoneAudioSample/FMWave.h b/audio/sysvad/PhoneAudioSample/FMWave.h
deleted file mode 100644
index 1134b680..00000000
--- a/audio/sysvad/PhoneAudioSample/FMWave.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- fmwave.h
-
-Abstract:
-
- Definition of wavert miniport class for fm
-
---*/
-
-#include "MinWaveRT.h"
-
-#ifndef _SYSVAD_FMMINWAVERT_H_
-#define _SYSVAD_FMMINWAVERT_H_
-
-NTSTATUS
-CreateFmMiniportWaveRT
-(
- _Out_ PUNKNOWN * Unknown,
- _In_ REFCLSID,
- _In_opt_ PUNKNOWN UnknownOuter,
- _When_((PoolType & NonPagedPoolMustSucceed) != 0,
- __drv_reportError("Must succeed pool allocations are forbidden. "
- "Allocation failures cause a system crash"))
- _In_ POOL_TYPE PoolType,
- _In_ PUNKNOWN UnknownAdapter,
- _In_opt_ PVOID DeviceContext,
- _In_ PENDPOINT_MINIPAIR MiniportPair
-);
-
-//=============================================================================
-// Classes
-//=============================================================================
-///////////////////////////////////////////////////////////////////////////////
-// CFmMiniportWaveRT
-//
-class CFmMiniportWaveRT :
- public CMiniportWaveRT,
- public IAdapterPowerManagement
-{
-private:
- BOOL m_bFmRxState;
-
-public:
- DECLARE_STD_UNKNOWN();
- IMP_IAdapterPowerManagement;
-
- CFmMiniportWaveRT(
- _In_ PUNKNOWN UnknownAdapter,
- _In_ PENDPOINT_MINIPAIR MiniportPair,
- _In_opt_ PVOID DeviceContext
- )
- :CMiniportWaveRT(UnknownAdapter, MiniportPair, DeviceContext),
- m_bFmRxState(FALSE)
- {
- }
-
- ~CFmMiniportWaveRT();
-
- friend NTSTATUS PropertyHandler_FmRxWaveFilter
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
-public:
- NTSTATUS PropertyHandler_FmRxState
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
-private:
- NTSTATUS UpdateTopologyJackState
- (
- _In_ BOOL NewState
- );
-};
-typedef CFmMiniportWaveRT *PCFmMiniportWaveRT;
-
-#endif // _SYSVAD_FMMINWAVERT_H_
-
diff --git a/audio/sysvad/PhoneAudioSample/handsetmictopo.cpp b/audio/sysvad/PhoneAudioSample/handsetmictopo.cpp
deleted file mode 100644
index 4e181c62..00000000
--- a/audio/sysvad/PhoneAudioSample/handsetmictopo.cpp
+++ /dev/null
@@ -1,274 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- handsetmictopo.cpp
-
-Abstract:
-
- Implementation of topology miniport for the handset mic (internal).
-
---*/
-
-#pragma warning (disable : 4127)
-
-#include <sysvad.h>
-#include "simple.h"
-#include "mintopo.h"
-#include "handsetmictopo.h"
-#include "handsetmictoptable.h"
-
-
-#pragma code_seg("PAGE")
-
-//=============================================================================
-NTSTATUS
-PropertyHandler_HandsetMicJackDescription
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION )
-
-Arguments:
-
- PropertyRequest -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandler_HandsetMicJackDescription]"));
-
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- ULONG nPinId = (ULONG)-1;
-
- ULONG cJackDescriptions = ARRAYSIZE(HandsetMicJackDescriptions);
- PKSJACK_DESCRIPTION * JackDescriptions = HandsetMicJackDescriptions;
-
- if (PropertyRequest->InstanceSize >= sizeof(ULONG))
- {
- nPinId = *(PULONG(PropertyRequest->Instance));
-
- if ((nPinId < cJackDescriptions) && (JackDescriptions[nPinId] != NULL))
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ntStatus =
- PropertyHandler_BasicSupport
- (
- PropertyRequest,
- KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
- VT_ILLEGAL
- );
- }
- else
- {
- ULONG cbNeeded = sizeof(KSMULTIPLE_ITEM) + sizeof(KSJACK_DESCRIPTION);
-
- if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = cbNeeded;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else if (PropertyRequest->ValueSize < cbNeeded)
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- PKSMULTIPLE_ITEM pMI = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
- PKSJACK_DESCRIPTION pDesc = (PKSJACK_DESCRIPTION)(pMI+1);
-
- pMI->Size = cbNeeded;
- pMI->Count = 1;
-
- RtlCopyMemory(pDesc, JackDescriptions[nPinId], sizeof(KSJACK_DESCRIPTION));
- ntStatus = STATUS_SUCCESS;
- }
- }
- }
- }
- }
-
- return ntStatus;
-}
-
-//=============================================================================
-NTSTATUS
-PropertyHandler_HandsetMicJackDescription2
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION2 )
-
-Arguments:
-
- PropertyRequest -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandler_HandsetMicJackDescription2]"));
-
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- ULONG nPinId = (ULONG)-1;
-
- ULONG cJackDescriptions = ARRAYSIZE(HandsetMicJackDescriptions);
- PKSJACK_DESCRIPTION * JackDescriptions = HandsetMicJackDescriptions;
-
- if (PropertyRequest->InstanceSize >= sizeof(ULONG))
- {
- nPinId = *(PULONG(PropertyRequest->Instance));
-
- if ((nPinId < cJackDescriptions) && (JackDescriptions[nPinId] != NULL))
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ntStatus =
- PropertyHandler_BasicSupport
- (
- PropertyRequest,
- KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
- VT_ILLEGAL
- );
- }
- else
- {
- ULONG cbNeeded = sizeof(KSMULTIPLE_ITEM) + sizeof(KSJACK_DESCRIPTION2);
-
- if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = cbNeeded;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else if (PropertyRequest->ValueSize < cbNeeded)
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- PKSMULTIPLE_ITEM pMI = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
- PKSJACK_DESCRIPTION2 pDesc = (PKSJACK_DESCRIPTION2)(pMI+1);
-
- pMI->Size = cbNeeded;
- pMI->Count = 1;
-
- RtlZeroMemory(pDesc, sizeof(KSJACK_DESCRIPTION2));
-
- //
- // Specifies the lower 16 bits of the DWORD parameter. This parameter indicates whether
- // the jack is currently active, streaming, idle, or hardware not ready.
- //
- pDesc->DeviceStateInfo = 0;
-
- //
- // From MSDN:
- // "If an audio device lacks jack presence detection, the IsConnected member of
- // the KSJACK_DESCRIPTION structure must always be set to TRUE. To remove the
- // ambiguity that results from this dual meaning of the TRUE value for IsConnected,
- // a client application can call IKsJackDescription2::GetJackDescription2 to read
- // the JackCapabilities flag of the KSJACK_DESCRIPTION2 structure. If this flag has
- // the JACKDESC2_PRESENCE_DETECT_CAPABILITY bit set, it indicates that the endpoint
- // does in fact support jack presence detection. In that case, the return value of
- // the IsConnected member can be interpreted to accurately reflect the insertion status
- // of the jack."
- //
- // Bit definitions:
- // 0x00000001 - JACKDESC2_PRESENCE_DETECT_CAPABILITY
- // 0x00000002 - JACKDESC2_DYNAMIC_FORMAT_CHANGE_CAPABILITY
- //
- pDesc->JackCapabilities = 0;
-
- ntStatus = STATUS_SUCCESS;
- }
- }
- }
- }
- }
-
- return ntStatus;
-}
-
-//=============================================================================
-NTSTATUS
-PropertyHandler_HandsetMicTopoFilter
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Redirects property request to miniport object
-
-Arguments:
-
- PropertyRequest -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandler_HandsetMicTopoFilter]"));
-
- // PropertryRequest structure is filled by portcls.
- // MajorTarget is a pointer to miniport object for miniports.
- //
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
-
- //
- // This line shows how to get a pointer to the miniport topology object.
- //
- PCMiniportTopology pMiniport = (PCMiniportTopology)PropertyRequest->MajorTarget;
- UNREFERENCED_VAR(pMiniport);
-
- if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Jack))
- {
- if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION)
- {
- ntStatus = PropertyHandler_HandsetMicJackDescription(PropertyRequest);
- }
- else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION2)
- {
- ntStatus = PropertyHandler_HandsetMicJackDescription2(PropertyRequest);
- }
- }
-
- return ntStatus;
-} // PropertyHandler_HandsetMicTopoFilter
-
-#pragma code_seg()
-
diff --git a/audio/sysvad/PhoneAudioSample/handsetmictopo.h b/audio/sysvad/PhoneAudioSample/handsetmictopo.h
deleted file mode 100644
index 07c8ba27..00000000
--- a/audio/sysvad/PhoneAudioSample/handsetmictopo.h
+++ /dev/null
@@ -1,21 +0,0 @@
-
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- handsetmictopo.h
-
-Abstract:
-
- Declaration of topology miniport for the handset mic (internal).
-
---*/
-
-#ifndef _SYSVAD_HANDSETMICTOPO_H_
-#define _SYSVAD_HANDSETMICTOPO_H_
-
-NTSTATUS PropertyHandler_HandsetMicTopoFilter(_In_ PPCPROPERTY_REQUEST PropertyRequest);
-
-#endif // _SYSVAD_HANDSETMICTOPO_H_
diff --git a/audio/sysvad/PhoneAudioSample/handsetmictoptable.h b/audio/sysvad/PhoneAudioSample/handsetmictoptable.h
deleted file mode 100644
index 5fd70010..00000000
--- a/audio/sysvad/PhoneAudioSample/handsetmictoptable.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- handsetmictopotable.h
-
-Abstract:
-
- Declaration of topology table for the handset mic (internal)
-
---*/
-
-#ifndef _SYSVAD_HANDSETMICTOPTABLE_H_
-#define _SYSVAD_HANDSETMICTOPTABLE_H_
-
-// Function declarations.
-NTSTATUS
-PropertyHandler_HandsetMicTopoFilter(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
-//=============================================================================
-static
-KSDATARANGE HandsetMicTopoPinDataRangesBridge[] =
-{
- {
- sizeof(KSDATARANGE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
- }
-};
-
-//=============================================================================
-static
-PKSDATARANGE HandsetMicTopoPinDataRangePointersBridge[] =
-{
- &HandsetMicTopoPinDataRangesBridge[0]
-};
-
-//=============================================================================
-static
-PCPIN_DESCRIPTOR HandsetMicTopoMiniportPins[] =
-{
- // KSPIN - topology filter in-pin
- {
- 0,
- 0,
- 0, // InstanceCount
- NULL, // AutomationTable
- { // KsPinDescriptor
- 0, // InterfacesCount
- NULL, // Interfaces
- 0, // MediumsCount
- NULL, // Mediums
- SIZEOF_ARRAY(HandsetMicTopoPinDataRangePointersBridge),// DataRangesCount
- HandsetMicTopoPinDataRangePointersBridge, // DataRanges
- KSPIN_DATAFLOW_IN, // DataFlow
- KSPIN_COMMUNICATION_NONE, // Communication
- &KSNODETYPE_HANDSET, // Category
- NULL, // Name
- 0 // Reserved
- }
- },
-
- // KSPIN - topology filter out-in
- {
- 0,
- 0,
- 0, // InstanceCount
- NULL, // AutomationTable
- { // KsPinDescriptor
- 0, // InterfacesCount
- NULL, // Interfaces
- 0, // MediumsCount
- NULL, // Mediums
- SIZEOF_ARRAY(HandsetMicTopoPinDataRangePointersBridge),// DataRangesCount
- HandsetMicTopoPinDataRangePointersBridge, // DataRanges
- KSPIN_DATAFLOW_OUT, // DataFlow
- KSPIN_COMMUNICATION_NONE, // Communication
- &KSCATEGORY_AUDIO, // Category
- NULL, // Name
- 0 // Reserved
- }
- }
-};
-
-//=============================================================================
-static
-KSJACK_DESCRIPTION HandsetMicJackDesc =
-{
- KSAUDIO_SPEAKER_MONO,
- 0x0000, // no color
- eConnTypeUnknown,
- eGeoLocTop,
- eGenLocInternal,
- ePortConnIntegratedDevice,
- TRUE
-};
-
-//=============================================================================
-// Only return a KSJACK_DESCRIPTION for the physical bridge pin.
-static
-PKSJACK_DESCRIPTION HandsetMicJackDescriptions[] =
-{
- &HandsetMicJackDesc,
- NULL
-};
-
-//=============================================================================
-static
-PCPROPERTY_ITEM HandsetMicPropertiesVolume[] =
-{
- {
- &KSPROPSETID_Audio,
- KSPROPERTY_AUDIO_VOLUMELEVEL,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_Topology
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationHandsetMicVolume, HandsetMicPropertiesVolume);
-
-//=============================================================================
-static
-PCPROPERTY_ITEM HandsetMicPropertiesMute[] =
-{
- {
- &KSPROPSETID_Audio,
- KSPROPERTY_AUDIO_MUTE,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_Topology
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationHandsetMicMute, HandsetMicPropertiesMute);
-
-//=============================================================================
-static
-PCPROPERTY_ITEM HandsetMicPropertiesPeakMeter[] =
-{
- {
- &KSPROPSETID_Audio,
- KSPROPERTY_AUDIO_PEAKMETER2,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_Topology
- },
- {
- &KSPROPSETID_Audio,
- KSPROPERTY_AUDIO_CPU_RESOURCES,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_Topology
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationHandsetMicPeakMeter, HandsetMicPropertiesPeakMeter);
-
-//=============================================================================
-static
-PCNODE_DESCRIPTOR HandsetMicTopologyNodes[] =
-{
- // KSNODE_TOPO_VOLUME
- {
- 0, // Flags
- &AutomationHandsetMicVolume, // AutomationTable
- &KSNODETYPE_VOLUME, // Type
- &KSAUDFNAME_MIC_VOLUME // Name
- },
- // KSNODE_TOPO_MUTE
- {
- 0, // Flags
- &AutomationHandsetMicMute, // AutomationTable
- &KSNODETYPE_MUTE, // Type
- &KSAUDFNAME_MIC_MUTE // Name
- },
- // KSNODE_TOPO_PEAKMETER
- {
- 0, // Flags
- &AutomationHandsetMicPeakMeter, // AutomationTable
- &KSNODETYPE_PEAKMETER, // Type
- &KSAUDFNAME_PEAKMETER // Name
- }
-};
-
-C_ASSERT( KSNODE_TOPO_VOLUME == 0 );
-C_ASSERT( KSNODE_TOPO_MUTE == 1 );
-C_ASSERT( KSNODE_TOPO_PEAKMETER == 2 );
-
-//=============================================================================
-static
-PCCONNECTION_DESCRIPTOR HandsetMicMiniportConnections[] =
-{
- // FromNode, FromPin, ToNode, ToPin
- { PCFILTER_NODE, KSPIN_TOPO_MIC_ELEMENTS, KSNODE_TOPO_VOLUME, 1 },
- { KSNODE_TOPO_VOLUME, 0, KSNODE_TOPO_MUTE, 1 },
- { KSNODE_TOPO_MUTE, 0, KSNODE_TOPO_PEAKMETER, 1 },
- { KSNODE_TOPO_PEAKMETER, 0, PCFILTER_NODE, KSPIN_TOPO_BRIDGE }
-};
-
-
-//=============================================================================
-static
-PCPROPERTY_ITEM HandsetMicPropertiesTopoFilter[] =
-{
- {
- &KSPROPSETID_Jack,
- KSPROPERTY_JACK_DESCRIPTION,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_HandsetMicTopoFilter
- },
- {
- &KSPROPSETID_Jack,
- KSPROPERTY_JACK_DESCRIPTION2,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_HandsetMicTopoFilter
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationHandsetMicTopoFilter, HandsetMicPropertiesTopoFilter);
-
-//=============================================================================
-static
-PCFILTER_DESCRIPTOR HandsetMicTopoMiniportFilterDescriptor =
-{
- 0, // Version
- &AutomationHandsetMicTopoFilter, // AutomationTable
- sizeof(PCPIN_DESCRIPTOR), // PinSize
- SIZEOF_ARRAY(HandsetMicTopoMiniportPins), // PinCount
- HandsetMicTopoMiniportPins, // Pins
- sizeof(PCNODE_DESCRIPTOR), // NodeSize
- SIZEOF_ARRAY(HandsetMicTopologyNodes), // NodeCount
- HandsetMicTopologyNodes, // Nodes
- SIZEOF_ARRAY(HandsetMicMiniportConnections), // ConnectionCount
- HandsetMicMiniportConnections, // Connections
- 0, // CategoryCount
- NULL // Categories
-};
-
-#endif // _SYSVAD_HANDSETMICTOPTABLE_H_
-
diff --git a/audio/sysvad/PhoneAudioSample/handsetmicwavtable.h b/audio/sysvad/PhoneAudioSample/handsetmicwavtable.h
deleted file mode 100644
index 5470e521..00000000
--- a/audio/sysvad/PhoneAudioSample/handsetmicwavtable.h
+++ /dev/null
@@ -1,447 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- handsetmicwavtable.h
-
-Abstract:
-
- Declaration of wave miniport tables for the handset microphone.
-
---*/
-
-#ifndef _SYSVAD_HANDSETMICWAVTABLE_H_
-#define _SYSVAD_HANDSETMICWAVTABLE_H_
-
-//
-// Handset microphone (internal) range.
-//
-#define HANDSETMIC_DEVICE_MAX_CHANNELS 1 // Max Channels.
-#define HANDSETMIC_MIN_BITS_PER_SAMPLE_PCM 16 // Min Bits Per Sample
-#define HANDSETMIC_MAX_BITS_PER_SAMPLE_PCM 16 // Max Bits Per Sample
-#define HANDSETMIC_MIN_SAMPLE_RATE 8000 // Min Sample Rate
-#define HANDSETMIC_MAX_SAMPLE_RATE 48000 // Max Sample Rate
-
-//
-// Max # of pin instances.
-//
-#define HANDSETMIC_MAX_INPUT_STREAMS 4
-
-//=============================================================================
-static
-KSDATAFORMAT_WAVEFORMATEXTENSIBLE HandsetMicPinSupportedDeviceFormats[] =
-{
- { // 0
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 1,
- 8000,
- 16000,
- 2,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_MONO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 1
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 1,
- 11025,
- 22050,
- 2,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_MONO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 2
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 1,
- 16000,
- 32000,
- 2,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_MONO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 3
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 1,
- 22050,
- 44100,
- 2,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_MONO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 4
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 1,
- 24000,
- 48000,
- 2,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_MONO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 5
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 1,
- 32000,
- 64000,
- 2,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_MONO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 6
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 1,
- 44100,
- 88200,
- 2,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_MONO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 7
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 1,
- 48000,
- 96000,
- 2,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_MONO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- }
-};
-
-//
-// Supported modes (only on streaming pins).
-//
-static
-MODE_AND_DEFAULT_FORMAT HandsetMicPinSupportedDeviceModes[] =
-{
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_RAW,
- &HandsetMicPinSupportedDeviceFormats[SIZEOF_ARRAY(HandsetMicPinSupportedDeviceFormats) - 1].DataFormat, // 48KHz
- },
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_DEFAULT,
- &HandsetMicPinSupportedDeviceFormats[SIZEOF_ARRAY(HandsetMicPinSupportedDeviceFormats) - 1].DataFormat, // 48KHz
- },
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_SPEECH,
- &HandsetMicPinSupportedDeviceFormats[2].DataFormat, // 16KHz
- },
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_COMMUNICATIONS,
- &HandsetMicPinSupportedDeviceFormats[4].DataFormat, // 24KHz
- }
-};
-
-//
-// The entries here must follow the same order as the filter's pin
-// descriptor array.
-//
-static
-PIN_DEVICE_FORMATS_AND_MODES HandsetMicPinDeviceFormatsAndModes[] =
-{
- {
- BridgePin,
- NULL,
- 0,
- NULL,
- 0
- },
- {
- SystemCapturePin,
- HandsetMicPinSupportedDeviceFormats,
- SIZEOF_ARRAY(HandsetMicPinSupportedDeviceFormats),
- HandsetMicPinSupportedDeviceModes,
- SIZEOF_ARRAY(HandsetMicPinSupportedDeviceModes)
- }
-};
-
-//=============================================================================
-static
-KSDATARANGE_AUDIO HandsetMicPinDataRangesStream[] =
-{
- {
- {
- sizeof(KSDATARANGE_AUDIO),
- KSDATARANGE_ATTRIBUTES, // An attributes list follows this data range
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- HANDSETMIC_DEVICE_MAX_CHANNELS,
- HANDSETMIC_MIN_BITS_PER_SAMPLE_PCM,
- HANDSETMIC_MAX_BITS_PER_SAMPLE_PCM,
- HANDSETMIC_MIN_SAMPLE_RATE,
- HANDSETMIC_MAX_SAMPLE_RATE
- },
-};
-
-static
-PKSDATARANGE HandsetMicPinDataRangePointersStream[] =
-{
- PKSDATARANGE(&HandsetMicPinDataRangesStream[0]),
- PKSDATARANGE(&PinDataRangeAttributeList),
-};
-
-//=============================================================================
-static
-KSDATARANGE HandsetMicPinDataRangesBridge[] =
-{
- {
- sizeof(KSDATARANGE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
- }
-};
-
-static
-PKSDATARANGE HandsetMicPinDataRangePointersBridge[] =
-{
- &HandsetMicPinDataRangesBridge[0]
-};
-
-//=============================================================================
-static
-PCPIN_DESCRIPTOR HandsetMicWaveMiniportPins[] =
-{
- // Wave In Bridge Pin (Capture - From Topology) KSPIN_WAVE_BRIDGE
- {
- 0,
- 0,
- 0,
- NULL,
- {
- 0,
- NULL,
- 0,
- NULL,
- SIZEOF_ARRAY(HandsetMicPinDataRangePointersBridge),
- HandsetMicPinDataRangePointersBridge,
- KSPIN_DATAFLOW_IN,
- KSPIN_COMMUNICATION_NONE,
- &KSCATEGORY_AUDIO,
- NULL,
- 0
- }
- },
-
- // Wave In Streaming Pin (Capture) KSPIN_WAVEIN_HOST
- {
- HANDSETMIC_MAX_INPUT_STREAMS,
- HANDSETMIC_MAX_INPUT_STREAMS,
- 0,
- NULL,
- {
- 0,
- NULL,
- 0,
- NULL,
- SIZEOF_ARRAY(HandsetMicPinDataRangePointersStream),
- HandsetMicPinDataRangePointersStream,
- KSPIN_DATAFLOW_OUT,
- KSPIN_COMMUNICATION_SINK,
- &KSCATEGORY_AUDIO,
- &KSAUDFNAME_RECORDING_CONTROL,
- 0
- }
- }
-};
-
-//=============================================================================
-static
-PCNODE_DESCRIPTOR HandsetMicWaveMiniportNodes[] =
-{
- // KSNODE_WAVE_ADC
- {
- 0, // Flags
- NULL, // AutomationTable
- &KSNODETYPE_ADC, // Type
- NULL // Name
- }
-};
-
-//=============================================================================
-static
-PCCONNECTION_DESCRIPTOR HandsetMicWaveMiniportConnections[] =
-{
- { PCFILTER_NODE, KSPIN_WAVE_BRIDGE, KSNODE_WAVE_ADC, 1 },
- { KSNODE_WAVE_ADC, 0, PCFILTER_NODE, KSPIN_WAVEIN_HOST }
-};
-
-//=============================================================================
-static
-PCPROPERTY_ITEM PropertiesHandsetMicWaveFilter[] =
-{
- {
- &KSPROPSETID_General,
- KSPROPERTY_GENERAL_COMPONENTID,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_WaveFilter
- },
- {
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_PROPOSEDATAFORMAT,
- KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_WaveFilter
- },
- {
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_PROPOSEDATAFORMAT2,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_WaveFilter
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationHandsetMicWaveFilter, PropertiesHandsetMicWaveFilter);
-
-//=============================================================================
-static
-PCFILTER_DESCRIPTOR HandsetMicWaveMiniportFilterDescriptor =
-{
- 0, // Version
- &AutomationHandsetMicWaveFilter, // AutomationTable
- sizeof(PCPIN_DESCRIPTOR), // PinSize
- SIZEOF_ARRAY(HandsetMicWaveMiniportPins), // PinCount
- HandsetMicWaveMiniportPins, // Pins
- sizeof(PCNODE_DESCRIPTOR), // NodeSize
- SIZEOF_ARRAY(HandsetMicWaveMiniportNodes), // NodeCount
- HandsetMicWaveMiniportNodes, // Nodes
- SIZEOF_ARRAY(HandsetMicWaveMiniportConnections), // ConnectionCount
- HandsetMicWaveMiniportConnections, // Connections
- 0, // CategoryCount
- NULL // Categories - use defaults (audio, render, capture)
-};
-
-#endif // _SYSVAD_HANDSETMICWAVTABLE_H_
diff --git a/audio/sysvad/PhoneAudioSample/handsetspeakertopo.h b/audio/sysvad/PhoneAudioSample/handsetspeakertopo.h
deleted file mode 100644
index 7b220f70..00000000
--- a/audio/sysvad/PhoneAudioSample/handsetspeakertopo.h
+++ /dev/null
@@ -1,86 +0,0 @@
-
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- handsetspeakertopo.h
-
-Abstract:
-
- Declaration of topology miniport for the handsetspeaker endpoint.
-
---*/
-
-#ifndef _SYSVAD_HANDSETSPEAKERTOPO_H_
-#define _SYSVAD_HANDSETSPEAKERTOPO_H_
-
-#include "basetopo.h"
-
-//=============================================================================
-// Classes
-//=============================================================================
-
-///////////////////////////////////////////////////////////////////////////////
-// CHandsetSpeakerMiniportTopology
-//
-
-class CHandsetSpeakerMiniportTopology :
- public CMiniportTopologySYSVAD,
- public IMiniportTopology,
- public CUnknown
-{
- public:
- DECLARE_STD_UNKNOWN();
- CHandsetSpeakerMiniportTopology
- (
- _In_opt_ PUNKNOWN UnknownOuter,
- _In_ PCFILTER_DESCRIPTOR *FilterDesc,
- _In_ USHORT DeviceMaxChannels
- )
- : CUnknown(UnknownOuter),
- CMiniportTopologySYSVAD(FilterDesc, DeviceMaxChannels)
- {}
-
- ~CHandsetSpeakerMiniportTopology();
-
- IMP_IMiniportTopology;
-
- NTSTATUS PropertyHandlerJackSinkInfo
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
- NTSTATUS PropertyHandlerJackDescription
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
- NTSTATUS PropertyHandlerJackDescription2
- (
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-};
-
-typedef CHandsetSpeakerMiniportTopology *PCHandsetSpeakerMiniportTopology;
-
-
-NTSTATUS
-CreateHandsetSpeakerMiniportTopology(
- _Out_ PUNKNOWN * Unknown,
- _In_ REFCLSID,
- _In_opt_ PUNKNOWN UnknownOuter,
- _When_((PoolType & NonPagedPoolMustSucceed) != 0,
- __drv_reportError("Must succeed pool allocations are forbidden. "
- "Allocation failures cause a system crash"))
- _In_ POOL_TYPE PoolType,
- _In_ PUNKNOWN UnknownAdapter,
- _In_opt_ PVOID DeviceContext,
- _In_ PENDPOINT_MINIPAIR MiniportPair
- );
-
-NTSTATUS PropertyHandler_HandsetSpeakerTopoFilter(_In_ PPCPROPERTY_REQUEST PropertyRequest);
-
-#endif // _SYSVAD_HANDSETSPEAKERTOPO_H_
-
diff --git a/audio/sysvad/PhoneAudioSample/handsetspeakertoptable.h b/audio/sysvad/PhoneAudioSample/handsetspeakertoptable.h
deleted file mode 100644
index 68873e61..00000000
--- a/audio/sysvad/PhoneAudioSample/handsetspeakertoptable.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- handsetspeakertoptable.h
-
-Abstract:
-
- Declaration of topology tables for the handsetspeaker endpoint.
-
---*/
-
-#ifndef _SYSVAD_HANDSETSPEAKERTOPTABLE_H_
-#define _SYSVAD_HANDSETSPEAKERTOPTABLE_H_
-
-//=============================================================================
-static
-KSDATARANGE HandsetSpeakerTopoPinDataRangesBridge[] =
-{
- {
- sizeof(KSDATARANGE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
- }
-};
-
-//=============================================================================
-static
-PKSDATARANGE HandsetSpeakerTopoPinDataRangePointersBridge[] =
-{
- &HandsetSpeakerTopoPinDataRangesBridge[0]
-};
-
-//=============================================================================
-static
-PCPIN_DESCRIPTOR HandsetSpeakerTopoMiniportPins[] =
-{
- // KSPIN_TOPO_WAVEOUT_SOURCE
- {
- 0,
- 0,
- 0, // InstanceCount
- NULL, // AutomationTable
- { // KsPinDescriptor
- 0, // InterfacesCount
- NULL, // Interfaces
- 0, // MediumsCount
- NULL, // Mediums
- SIZEOF_ARRAY(HandsetSpeakerTopoPinDataRangePointersBridge), // DataRangesCount
- HandsetSpeakerTopoPinDataRangePointersBridge, // DataRanges
- KSPIN_DATAFLOW_IN, // DataFlow
- KSPIN_COMMUNICATION_NONE, // Communication
- &KSCATEGORY_AUDIO, // Category
- NULL, // Name
- 0 // Reserved
- }
- },
- // KSPIN_TOPO_LINEOUT_DEST
- {
- 0,
- 0,
- 0, // InstanceCount
- NULL, // AutomationTable
- { // KsPinDescriptor
- 0, // InterfacesCount
- NULL, // Interfaces
- 0, // MediumsCount
- NULL, // Mediums
- SIZEOF_ARRAY(HandsetSpeakerTopoPinDataRangePointersBridge), // DataRangesCount
- HandsetSpeakerTopoPinDataRangePointersBridge, // DataRanges
- KSPIN_DATAFLOW_OUT, // DataFlow
- KSPIN_COMMUNICATION_NONE, // Communication
- &KSNODETYPE_HANDSET, // Category
- NULL, // Name
- 0 // Reserved
- }
- }
-};
-
-//=============================================================================
-static
-KSJACK_DESCRIPTION HandsetSpeakerJackDesc =
-{
- KSAUDIO_SPEAKER_MONO,
- 0x0000, // no color
- eConnTypeUnknown,
- eGeoLocBottom,
- eGenLocInternal,
- ePortConnIntegratedDevice,
- TRUE
-};
-
-// Only return a KSJACK_DESCRIPTION for the physical bridge pin.
-static
-PKSJACK_DESCRIPTION HandsetSpeakerJackDescriptions[] =
-{
- NULL,
- &HandsetSpeakerJackDesc
-};
-
-//=============================================================================
-static
-PCCONNECTION_DESCRIPTOR HandsetSpeakerTopoMiniportConnections[] =
-{
- // FromNode, FromPin, ToNode, ToPin
- { PCFILTER_NODE, KSPIN_TOPO_WAVEOUT_SOURCE, PCFILTER_NODE, KSPIN_TOPO_LINEOUT_DEST}
-};
-
-
-//=============================================================================
-static
-PCPROPERTY_ITEM PropertiesHandsetSpeakerTopoFilter[] =
-{
- {
- &KSPROPSETID_Jack,
- KSPROPERTY_JACK_DESCRIPTION,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_HandsetSpeakerTopoFilter
- },
- {
- &KSPROPSETID_Jack,
- KSPROPERTY_JACK_DESCRIPTION2,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_HandsetSpeakerTopoFilter
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationHandsetSpeakerTopoFilter, PropertiesHandsetSpeakerTopoFilter);
-
-//=============================================================================
-static
-PCFILTER_DESCRIPTOR HandsetSpeakerTopoMiniportFilterDescriptor =
-{
- 0, // Version
- &AutomationHandsetSpeakerTopoFilter, // AutomationTable
- sizeof(PCPIN_DESCRIPTOR), // PinSize
- SIZEOF_ARRAY(HandsetSpeakerTopoMiniportPins), // PinCount
- HandsetSpeakerTopoMiniportPins, // Pins
- sizeof(PCNODE_DESCRIPTOR), // NodeSize
- 0, // NodeCount
- NULL, // Nodes
- SIZEOF_ARRAY(HandsetSpeakerTopoMiniportConnections), // ConnectionCount
- HandsetSpeakerTopoMiniportConnections, // Connections
- 0, // CategoryCount
- NULL // Categories
-};
-
-#endif // _SYSVAD_HANDSETSPEAKERTOPTABLE_H_
-
-
diff --git a/audio/sysvad/PhoneAudioSample/handsetspeakerwavtable.h b/audio/sysvad/PhoneAudioSample/handsetspeakerwavtable.h
deleted file mode 100644
index 73548626..00000000
--- a/audio/sysvad/PhoneAudioSample/handsetspeakerwavtable.h
+++ /dev/null
@@ -1,550 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- handsetspeakerwavtable.h
-
-Abstract:
-
- Declaration of wave miniport tables for the handsetspeaker endpoint.
-
- Note: the HANDSETSPEAKER in this sample shows how to do h/w loopback
- for non-offloaded devices.
-
---*/
-
-#ifndef _SYSVAD_HANDSETSPEAKERWAVTABLE_H_
-#define _SYSVAD_HANDSETSPEAKERWAVTABLE_H_
-
-
-// To keep the code simple assume device supports only 48KHz, 16-bit, stereo (PCM and NON-PCM)
-
-
-#define HANDSETSPEAKER_DEVICE_MAX_CHANNELS 2 // Max Channels.
-
-#define HANDSETSPEAKER_HOST_MAX_CHANNELS 2 // Max Channels.
-#define HANDSETSPEAKER_HOST_MIN_BITS_PER_SAMPLE 16 // Min Bits Per Sample
-#define HANDSETSPEAKER_HOST_MAX_BITS_PER_SAMPLE 16 // Max Bits Per Sample
-#define HANDSETSPEAKER_HOST_MIN_SAMPLE_RATE 24000 // Min Sample Rate
-#define HANDSETSPEAKER_HOST_MAX_SAMPLE_RATE 96000 // Max Sample Rate
-
-#define HANDSETSPEAKER_LOOPBACK_MAX_CHANNELS HANDSETSPEAKER_HOST_MAX_CHANNELS // Must be equal to host pin's Max Channels.
-#define HANDSETSPEAKER_LOOPBACK_MIN_BITS_PER_SAMPLE HANDSETSPEAKER_HOST_MIN_BITS_PER_SAMPLE // Must be equal to host pin's Min Bits Per Sample
-#define HANDSETSPEAKER_LOOPBACK_MAX_BITS_PER_SAMPLE HANDSETSPEAKER_HOST_MAX_BITS_PER_SAMPLE // Must be equal to host pin's Max Bits Per Sample
-#define HANDSETSPEAKER_LOOPBACK_MIN_SAMPLE_RATE HANDSETSPEAKER_HOST_MIN_SAMPLE_RATE // Must be equal to host pin's Min Sample Rate
-#define HANDSETSPEAKER_LOOPBACK_MAX_SAMPLE_RATE HANDSETSPEAKER_HOST_MAX_SAMPLE_RATE // Must be equal to host pin's Max Sample Rate
-
-#define HANDSETSPEAKER_DOLBY_DIGITAL_MAX_CHANNELS 2 // Max Channels.
-#define HANDSETSPEAKER_DOLBY_DIGITAL_MIN_BITS_PER_SAMPLE 16 // Min Bits Per Sample
-#define HANDSETSPEAKER_DOLBY_DIGITAL_MAX_BITS_PER_SAMPLE 16 // Max Bits Per Sample
-#define HANDSETSPEAKER_DOLBY_DIGITAL_MIN_SAMPLE_RATE 44100 // Min Sample Rate
-#define HANDSETSPEAKER_DOLBY_DIGITAL_MAX_SAMPLE_RATE 44100 // Max Sample Rate
-
-//
-// Max # of pin instances.
-//
-#define HANDSETSPEAKER_MAX_INPUT_SYSTEM_STREAMS 3
-#define HANDSETSPEAKER_MAX_OUTPUT_LOOPBACK_STREAMS MAX_OUTPUT_LOOPBACK_STREAMS
-
-//=============================================================================
-static
-KSDATAFORMAT_WAVEFORMATEXTENSIBLE HandsetSpeakerHostPinSupportedDeviceFormats[] =
-{
- { // 0
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 24000,
- 96000,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 1
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 32000,
- 128000,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 2
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 44100,
- 176400,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 3
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 48000,
- 192000,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 4
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 88200,
- 352800,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 5
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 96000,
- 384000,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- }
-};
-
-//
-// Supported modes (only on streaming pins).
-//
-static
-MODE_AND_DEFAULT_FORMAT HandsetSpeakerHostPinSupportedDeviceModes[] =
-{
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_RAW,
- &HandsetSpeakerHostPinSupportedDeviceFormats[3].DataFormat, // 48KHz
- },
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_DEFAULT,
- &HandsetSpeakerHostPinSupportedDeviceFormats[3].DataFormat, // 48KHz
- },
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_COMMUNICATIONS,
- &HandsetSpeakerHostPinSupportedDeviceFormats[0].DataFormat, // 24KHz
- }
-};
-
-//
-// The entries here must follow the same order as the filter's pin
-// descriptor array.
-//
-static
-PIN_DEVICE_FORMATS_AND_MODES HandsetSpeakerPinDeviceFormatsAndModes[] =
-{
- {
- SystemRenderPin,
- HandsetSpeakerHostPinSupportedDeviceFormats,
- SIZEOF_ARRAY(HandsetSpeakerHostPinSupportedDeviceFormats),
- HandsetSpeakerHostPinSupportedDeviceModes,
- SIZEOF_ARRAY(HandsetSpeakerHostPinSupportedDeviceModes)
- },
- {
- RenderLoopbackPin,
- HandsetSpeakerHostPinSupportedDeviceFormats, // Must support all the formats supported by host pin
- SIZEOF_ARRAY(HandsetSpeakerHostPinSupportedDeviceFormats),
- NULL, // loopback doesn't support modes.
- 0
- },
- {
- BridgePin,
- NULL,
- 0,
- NULL,
- 0
- }
-};
-
-//=============================================================================
-static
-KSDATARANGE_AUDIO HandsetSpeakerPinDataRangesStream[] =
-{
- { // 0
- {
- sizeof(KSDATARANGE_AUDIO),
- KSDATARANGE_ATTRIBUTES, // An attributes list follows this data range
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- HANDSETSPEAKER_HOST_MAX_CHANNELS,
- HANDSETSPEAKER_HOST_MIN_BITS_PER_SAMPLE,
- HANDSETSPEAKER_HOST_MAX_BITS_PER_SAMPLE,
- HANDSETSPEAKER_HOST_MIN_SAMPLE_RATE,
- HANDSETSPEAKER_HOST_MAX_SAMPLE_RATE
- },
- { // 1
- {
- sizeof(KSDATARANGE_AUDIO),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- HANDSETSPEAKER_LOOPBACK_MAX_CHANNELS,
- HANDSETSPEAKER_LOOPBACK_MIN_BITS_PER_SAMPLE,
- HANDSETSPEAKER_LOOPBACK_MAX_BITS_PER_SAMPLE,
- HANDSETSPEAKER_LOOPBACK_MIN_SAMPLE_RATE,
- HANDSETSPEAKER_LOOPBACK_MAX_SAMPLE_RATE
- }
-};
-
-static
-PKSDATARANGE HandsetSpeakerPinDataRangePointersStream[] =
-{
- PKSDATARANGE(&HandsetSpeakerPinDataRangesStream[0]),
- PKSDATARANGE(&PinDataRangeAttributeList)
-};
-
-static
-PKSDATARANGE HandsetSpeakerPinDataRangePointersLoopbackStream[] =
-{
- PKSDATARANGE(&HandsetSpeakerPinDataRangesStream[1])
-};
-
-//=============================================================================
-static
-KSDATARANGE HandsetSpeakerPinDataRangesBridge[] =
-{
- {
- sizeof(KSDATARANGE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
- }
-};
-
-static
-PKSDATARANGE HandsetSpeakerPinDataRangePointersBridge[] =
-{
- &HandsetSpeakerPinDataRangesBridge[0]
-};
-
-
-//=============================================================================
-static
-PCPIN_DESCRIPTOR HandsetSpeakerWaveMiniportPins[] =
-{
- // Wave Out Streaming Pin (Renderer) KSPIN_WAVE_RENDER2_SINK_SYSTEM
- {
- HANDSETSPEAKER_MAX_INPUT_SYSTEM_STREAMS,
- HANDSETSPEAKER_MAX_INPUT_SYSTEM_STREAMS,
- 0,
- NULL,
- {
- 0,
- NULL,
- 0,
- NULL,
- SIZEOF_ARRAY(HandsetSpeakerPinDataRangePointersStream),
- HandsetSpeakerPinDataRangePointersStream,
- KSPIN_DATAFLOW_IN,
- KSPIN_COMMUNICATION_SINK,
- &KSCATEGORY_AUDIO,
- NULL,
- 0
- }
- },
- // Wave Out Streaming Pin (Renderer) KSPIN_WAVE_RENDER2_SINK_LOOPBACK
- {
- HANDSETSPEAKER_MAX_OUTPUT_LOOPBACK_STREAMS,
- HANDSETSPEAKER_MAX_OUTPUT_LOOPBACK_STREAMS,
- 0,
- NULL,
- {
- 0,
- NULL,
- 0,
- NULL,
- SIZEOF_ARRAY(HandsetSpeakerPinDataRangePointersLoopbackStream),
- HandsetSpeakerPinDataRangePointersLoopbackStream,
- KSPIN_DATAFLOW_OUT,
- KSPIN_COMMUNICATION_SINK,
- &KSNODETYPE_AUDIO_LOOPBACK,
- NULL,
- 0
- }
- },
- // Wave Out Bridge Pin (Renderer) KSPIN_WAVE_RENDER2_SOURCE
- {
- 0,
- 0,
- 0,
- NULL,
- {
- 0,
- NULL,
- 0,
- NULL,
- SIZEOF_ARRAY(HandsetSpeakerPinDataRangePointersBridge),
- HandsetSpeakerPinDataRangePointersBridge,
- KSPIN_DATAFLOW_OUT,
- KSPIN_COMMUNICATION_NONE,
- &KSCATEGORY_AUDIO,
- NULL,
- 0
- }
- },
-};
-
-//=============================================================================
-static
-PCPROPERTY_ITEM HandsetSpeakerPropertiesVolume[] =
-{
- {
- &KSPROPSETID_Audio,
- KSPROPERTY_AUDIO_VOLUMELEVEL,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_WaveFilter
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationHandsetSpeakerVolume, HandsetSpeakerPropertiesVolume);
-
-//=============================================================================
-static
-PCPROPERTY_ITEM HandsetSpeakerPropertiesMute[] =
-{
- {
- &KSPROPSETID_Audio,
- KSPROPERTY_AUDIO_MUTE,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_WaveFilter
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationHandsetSpeakerMute, HandsetSpeakerPropertiesMute);
-
-//=============================================================================
-static
-PCPROPERTY_ITEM HandsetSpeakerPropertiesPeakMeter[] =
-{
- {
- &KSPROPSETID_Audio,
- KSPROPERTY_AUDIO_PEAKMETER2,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_WaveFilter
- },
- {
- &KSPROPSETID_Audio,
- KSPROPERTY_AUDIO_CPU_RESOURCES,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_WaveFilter
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationHandsetSpeakerPeakMeter, HandsetSpeakerPropertiesPeakMeter);
-
-//=============================================================================
-static
-PCNODE_DESCRIPTOR HandsetSpeakerWaveMiniportNodes[] =
-{
- // KSNODE_WAVE_SUM
- {
- 0, // Flags
- NULL, // AutomationTable
- &KSNODETYPE_SUM, // Type
- NULL // Name
- },
- // KSNODE_WAVE_VOLUME
- {
- 0, // Flags
- &AutomationHandsetSpeakerVolume, // AutomationTable
- &KSNODETYPE_VOLUME, // Type
- &KSAUDFNAME_WAVE_VOLUME // Name
- },
- // KSNODE_WAVE_MUTE
- {
- 0, // Flags
- &AutomationHandsetSpeakerMute, // AutomationTable
- &KSNODETYPE_MUTE, // Type
- &KSAUDFNAME_WAVE_MUTE // Name
- },
- // KSNODE_WAVE_PEAKMETER
- {
- 0, // Flags
- &AutomationHandsetSpeakerPeakMeter, // AutomationTable
- &KSNODETYPE_PEAKMETER, // Type
- &KSAUDFNAME_PEAKMETER // Name
- }
-};
-
-C_ASSERT( KSNODE_WAVE_SUM == 0 );
-C_ASSERT( KSNODE_WAVE_VOLUME == 1 );
-C_ASSERT( KSNODE_WAVE_MUTE == 2 );
-C_ASSERT( KSNODE_WAVE_PEAKMETER == 3 );
-
-
-//=============================================================================
-//
-// Note:
-// 1) A sum node can be used to 'sum' multiple streams associated to different
-// instances of the same pin.
-// 2) Any node output has an implicit 'tee' node associated with it. Thus in the
-// scenario below it is ok for the peak meter node to have two identical outputs.
-//
-// ----------------------------------------------------------
-// | |
-// System Pin 0 | |-----| |--------| |------| |-----------| |--> 1 Loopback Pin
-// [instances:0...n]-->| -->| Sum |--->| Volume |-->| Mute |-->| PeakMeter |--> |
-// | |-----| |--------| |------| |-----------| |--> 2 KSPIN_WAVE_RENDER2_SOURCE
-// | |
-// ----------------------------------------------------------
-
-static
-PCCONNECTION_DESCRIPTOR HandsetSpeakerWaveMiniportConnections[] =
-{
- { PCFILTER_NODE, KSPIN_WAVE_RENDER2_SINK_SYSTEM, KSNODE_WAVE_SUM, 1 },
- { KSNODE_WAVE_SUM, 0, KSNODE_WAVE_VOLUME, 1 },
- { KSNODE_WAVE_VOLUME, 0, KSNODE_WAVE_MUTE, 1 },
- { KSNODE_WAVE_MUTE, 0, KSNODE_WAVE_PEAKMETER, 1 },
- { KSNODE_WAVE_PEAKMETER, 2, PCFILTER_NODE, KSPIN_WAVE_RENDER2_SINK_LOOPBACK },
- { KSNODE_WAVE_PEAKMETER, 0, PCFILTER_NODE, KSPIN_WAVE_RENDER2_SOURCE },
-};
-
-//=============================================================================
-static
-PCPROPERTY_ITEM PropertiesHandsetSpeakerWaveFilter[] =
-{
- {
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_PROPOSEDATAFORMAT,
- KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_WaveFilter
- },
- {
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_PROPOSEDATAFORMAT2,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_WaveFilter
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationHandsetSpeakerWaveFilter, PropertiesHandsetSpeakerWaveFilter);
-
-//=============================================================================
-static
-PCFILTER_DESCRIPTOR HandsetSpeakerWaveMiniportFilterDescriptor =
-{
- 0, // Version
- &AutomationHandsetSpeakerWaveFilter, // AutomationTable
- sizeof(PCPIN_DESCRIPTOR), // PinSize
- SIZEOF_ARRAY(HandsetSpeakerWaveMiniportPins), // PinCount
- HandsetSpeakerWaveMiniportPins, // Pins
- sizeof(PCNODE_DESCRIPTOR), // NodeSize
- SIZEOF_ARRAY(HandsetSpeakerWaveMiniportNodes), // NodeCount
- HandsetSpeakerWaveMiniportNodes, // Nodes
- SIZEOF_ARRAY(HandsetSpeakerWaveMiniportConnections), // ConnectionCount
- HandsetSpeakerWaveMiniportConnections, // Connections
- 0, // CategoryCount
- NULL // Categories - use defaults (audio, render, capture)
-};
-
-#endif // _SYSVAD_HANDSETSPEAKERWAVTABLE_H_
-
diff --git a/audio/sysvad/PhoneAudioSample/michstopo.cpp b/audio/sysvad/PhoneAudioSample/michstopo.cpp
deleted file mode 100644
index f96a58e5..00000000
--- a/audio/sysvad/PhoneAudioSample/michstopo.cpp
+++ /dev/null
@@ -1,275 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- michstopo.cpp
-
-Abstract:
-
- Implementation of topology miniport for the mic (external: headset).
-
---*/
-
-#pragma warning (disable : 4127)
-
-#include <sysvad.h>
-#include "simple.h"
-#include "mintopo.h"
-#include "michstopo.h"
-#include "michstoptable.h"
-
-
-#pragma code_seg("PAGE")
-
-//=============================================================================
-NTSTATUS
-PropertyHandler_MicHsJackDescription
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION )
-
-Arguments:
-
- PropertyRequest -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandler_MicHsJackDescription]"));
-
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- ULONG nPinId = (ULONG)-1;
-
- ULONG cJackDescriptions = ARRAYSIZE(MicHsJackDescriptions);
- PKSJACK_DESCRIPTION * JackDescriptions = MicHsJackDescriptions;
-
- if (PropertyRequest->InstanceSize >= sizeof(ULONG))
- {
- nPinId = *(PULONG(PropertyRequest->Instance));
-
- if ((nPinId < cJackDescriptions) && (JackDescriptions[nPinId] != NULL))
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ntStatus =
- PropertyHandler_BasicSupport
- (
- PropertyRequest,
- KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
- VT_ILLEGAL
- );
- }
- else
- {
- ULONG cbNeeded = sizeof(KSMULTIPLE_ITEM) + sizeof(KSJACK_DESCRIPTION);
-
- if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = cbNeeded;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else if (PropertyRequest->ValueSize < cbNeeded)
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- PKSMULTIPLE_ITEM pMI = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
- PKSJACK_DESCRIPTION pDesc = (PKSJACK_DESCRIPTION)(pMI+1);
-
- pMI->Size = cbNeeded;
- pMI->Count = 1;
-
- RtlCopyMemory(pDesc, JackDescriptions[nPinId], sizeof(KSJACK_DESCRIPTION));
- ntStatus = STATUS_SUCCESS;
- }
- }
- }
- }
- }
-
- return ntStatus;
-}
-
-//=============================================================================
-NTSTATUS
-PropertyHandler_MicHsJackDescription2
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION2 )
-
-Arguments:
-
- PropertyRequest -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandler_MicHsJackDescription2]"));
-
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- ULONG nPinId = (ULONG)-1;
-
- ULONG cJackDescriptions = ARRAYSIZE(MicHsJackDescriptions);
- PKSJACK_DESCRIPTION * JackDescriptions = MicHsJackDescriptions;
-
- if (PropertyRequest->InstanceSize >= sizeof(ULONG))
- {
- nPinId = *(PULONG(PropertyRequest->Instance));
-
- if ((nPinId < cJackDescriptions) && (JackDescriptions[nPinId] != NULL))
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ntStatus =
- PropertyHandler_BasicSupport
- (
- PropertyRequest,
- KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
- VT_ILLEGAL
- );
- }
- else
- {
- ULONG cbNeeded = sizeof(KSMULTIPLE_ITEM) + sizeof(KSJACK_DESCRIPTION2);
-
- if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = cbNeeded;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else if (PropertyRequest->ValueSize < cbNeeded)
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- PKSMULTIPLE_ITEM pMI = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
- PKSJACK_DESCRIPTION2 pDesc = (PKSJACK_DESCRIPTION2)(pMI+1);
-
- pMI->Size = cbNeeded;
- pMI->Count = 1;
-
- RtlZeroMemory(pDesc, sizeof(KSJACK_DESCRIPTION2));
-
- //
- // Specifies the lower 16 bits of the DWORD parameter. This parameter indicates whether
- // the jack is currently active, streaming, idle, or hardware not ready.
- //
- pDesc->DeviceStateInfo = 0;
-
- //
- // From MSDN:
- // "If an audio device lacks jack presence detection, the IsConnected member of
- // the KSJACK_DESCRIPTION structure must always be set to TRUE. To remove the
- // ambiguity that results from this dual meaning of the TRUE value for IsConnected,
- // a client application can call IKsJackDescription2::GetJackDescription2 to read
- // the JackCapabilities flag of the KSJACK_DESCRIPTION2 structure. If this flag has
- // the JACKDESC2_PRESENCE_DETECT_CAPABILITY bit set, it indicates that the endpoint
- // does in fact support jack presence detection. In that case, the return value of
- // the IsConnected member can be interpreted to accurately reflect the insertion status
- // of the jack."
- //
- // Bit definitions:
- // 0x00000001 - JACKDESC2_PRESENCE_DETECT_CAPABILITY
- // 0x00000002 - JACKDESC2_DYNAMIC_FORMAT_CHANGE_CAPABILITY
- //
- pDesc->JackCapabilities = JACKDESC2_PRESENCE_DETECT_CAPABILITY;
-
- ntStatus = STATUS_SUCCESS;
- }
- }
- }
- }
- }
-
- return ntStatus;
-}
-
-
-//=============================================================================
-NTSTATUS
-PropertyHandler_MicHsTopoFilter
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Redirects property request to miniport object
-
-Arguments:
-
- PropertyRequest -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandler_MicHsTopoFilter]"));
-
- // PropertryRequest structure is filled by portcls.
- // MajorTarget is a pointer to miniport object for miniports.
- //
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
-
- //
- // This line shows how to get a pointer to the miniport topology object.
- //
- PCMiniportTopology pMiniport = (PCMiniportTopology)PropertyRequest->MajorTarget;
- UNREFERENCED_VAR(pMiniport);
-
- if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Jack))
- {
- if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION)
- {
- ntStatus = PropertyHandler_MicHsJackDescription(PropertyRequest);
- }
- else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION2)
- {
- ntStatus = PropertyHandler_MicHsJackDescription2(PropertyRequest);
- }
- }
-
- return ntStatus;
-} // PropertyHandler_MicHsTopoFilter
-
-#pragma code_seg()
-
diff --git a/audio/sysvad/PhoneAudioSample/michstopo.h b/audio/sysvad/PhoneAudioSample/michstopo.h
deleted file mode 100644
index b8f9b106..00000000
--- a/audio/sysvad/PhoneAudioSample/michstopo.h
+++ /dev/null
@@ -1,21 +0,0 @@
-
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- michstopo.h
-
-Abstract:
-
- Declaration of topology miniport for the mic (external: headset).
-
---*/
-
-#ifndef _SYSVAD_MICHSTOPO_H_
-#define _SYSVAD_MICHSTOPO_H_
-
-NTSTATUS PropertyHandler_MicHsTopoFilter(_In_ PPCPROPERTY_REQUEST PropertyRequest);
-
-#endif // _SYSVAD_MICHSTOPO_H_
diff --git a/audio/sysvad/PhoneAudioSample/michstoptable.h b/audio/sysvad/PhoneAudioSample/michstoptable.h
deleted file mode 100644
index 0b4ed73c..00000000
--- a/audio/sysvad/PhoneAudioSample/michstoptable.h
+++ /dev/null
@@ -1,257 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- michstopotable.h
-
-Abstract:
-
- Declaration of topology table for the mic (external: headset)
-
---*/
-
-#ifndef _SYSVAD_MICHSTOPTABLE_H_
-#define _SYSVAD_MICHSTOPTABLE_H_
-
-#include <mintopo.h>
-
-// Function declarations.
-NTSTATUS
-PropertyHandler_MicHsTopoFilter(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
- );
-
-//=============================================================================
-static
-KSDATARANGE MicHsTopoPinDataRangesBridge[] =
-{
- {
- sizeof(KSDATARANGE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
- }
-};
-
-//=============================================================================
-static
-PKSDATARANGE MicHsTopoPinDataRangePointersBridge[] =
-{
- &MicHsTopoPinDataRangesBridge[0]
-};
-
-//=============================================================================
-static
-PCPIN_DESCRIPTOR MicHsTopoMiniportPins[] =
-{
- // KSPIN - topology filter in-pin
- {
- 0,
- 0,
- 0, // InstanceCount
- NULL, // AutomationTable
- { // KsPinDescriptor
- 0, // InterfacesCount
- NULL, // Interfaces
- 0, // MediumsCount
- NULL, // Mediums
- SIZEOF_ARRAY(MicHsTopoPinDataRangePointersBridge),// DataRangesCount
- MicHsTopoPinDataRangePointersBridge, // DataRanges
- KSPIN_DATAFLOW_IN, // DataFlow
- KSPIN_COMMUNICATION_NONE, // Communication
- &KSNODETYPE_HEADSET_MICROPHONE, // Category
- NULL, // Name
- 0 // Reserved
- }
- },
-
- // KSPIN - topology filter out-in
- {
- 0,
- 0,
- 0, // InstanceCount
- NULL, // AutomationTable
- { // KsPinDescriptor
- 0, // InterfacesCount
- NULL, // Interfaces
- 0, // MediumsCount
- NULL, // Mediums
- SIZEOF_ARRAY(MicHsTopoPinDataRangePointersBridge),// DataRangesCount
- MicHsTopoPinDataRangePointersBridge, // DataRanges
- KSPIN_DATAFLOW_OUT, // DataFlow
- KSPIN_COMMUNICATION_NONE, // Communication
- &KSCATEGORY_AUDIO, // Category
- NULL, // Name
- 0 // Reserved
- }
- }
-};
-
-//=============================================================================
-static
-KSJACK_DESCRIPTION MicHsJackDesc =
-{
- KSAUDIO_SPEAKER_MONO,
- JACKDESC_RGB(179, 201, 140),
- eConnTypeCombination,
- eGeoLocRear,
- eGenLocPrimaryBox,
- ePortConnJack,
- FALSE // NOTE: For convenience, wired headset jacks will be "unplugged" at boot.
-};
-
-//=============================================================================
-// Only return a KSJACK_DESCRIPTION for the physical bridge pin.
-static
-PKSJACK_DESCRIPTION MicHsJackDescriptions[] =
-{
- &MicHsJackDesc,
- NULL
-};
-
-//=============================================================================
-static
-PCPROPERTY_ITEM MicHsPropertiesVolume[] =
-{
- {
- &KSPROPSETID_Audio,
- KSPROPERTY_AUDIO_VOLUMELEVEL,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_Topology
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationMicHsVolume, MicHsPropertiesVolume);
-
-//=============================================================================
-static
-PCPROPERTY_ITEM MicHsPropertiesMute[] =
-{
- {
- &KSPROPSETID_Audio,
- KSPROPERTY_AUDIO_MUTE,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_Topology
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationMicHsMute, MicHsPropertiesMute);
-
-//=============================================================================
-static
-PCPROPERTY_ITEM MicHsPropertiesPeakMeter[] =
-{
- {
- &KSPROPSETID_Audio,
- KSPROPERTY_AUDIO_PEAKMETER2,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_Topology
- },
- {
- &KSPROPSETID_Audio,
- KSPROPERTY_AUDIO_CPU_RESOURCES,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_Topology
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationMicHsPeakMeter, MicHsPropertiesPeakMeter);
-
-//=============================================================================
-static
-PCNODE_DESCRIPTOR MicHsTopologyNodes[] =
-{
- // KSNODE_TOPO_VOLUME
- {
- 0, // Flags
- &AutomationMicHsVolume, // AutomationTable
- &KSNODETYPE_VOLUME, // Type
- &KSAUDFNAME_MIC_VOLUME // Name
- },
- // KSNODE_TOPO_MUTE
- {
- 0, // Flags
- &AutomationMicHsMute, // AutomationTable
- &KSNODETYPE_MUTE, // Type
- &KSAUDFNAME_MIC_MUTE // Name
- },
- // KSNODE_TOPO_PEAKMETER
- {
- 0, // Flags
- &AutomationMicHsPeakMeter, // AutomationTable
- &KSNODETYPE_PEAKMETER, // Type
- &KSAUDFNAME_PEAKMETER // Name
- }
-};
-
-C_ASSERT( KSNODE_TOPO_VOLUME == 0 );
-C_ASSERT( KSNODE_TOPO_MUTE == 1 );
-C_ASSERT( KSNODE_TOPO_PEAKMETER == 2 );
-
-//=============================================================================
-static
-PCCONNECTION_DESCRIPTOR MicHsMiniportConnections[] =
-{
- // FromNode, FromPin, ToNode, ToPin
- { PCFILTER_NODE, KSPIN_TOPO_MIC_ELEMENTS, KSNODE_TOPO_VOLUME, 1 },
- { KSNODE_TOPO_VOLUME, 0, KSNODE_TOPO_MUTE, 1 },
- { KSNODE_TOPO_MUTE, 0, KSNODE_TOPO_PEAKMETER, 1 },
- { KSNODE_TOPO_PEAKMETER, 0, PCFILTER_NODE, KSPIN_TOPO_BRIDGE }
-};
-
-
-//=============================================================================
-static
-PCPROPERTY_ITEM MicHsPropertiesTopoFilter[] =
-{
- {
- &KSPROPSETID_Jack,
- KSPROPERTY_JACK_DESCRIPTION,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_MicHsTopoFilter
- },
- {
- &KSPROPSETID_Jack,
- KSPROPERTY_JACK_DESCRIPTION2,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_MicHsTopoFilter
- }
-};
-
-static PCEVENT_ITEM MicHsJackInfoChangeEvent[] =
-{
- {
- &KSEVENTSETID_PinCapsChange, // Something changed
- KSEVENT_PINCAPS_JACKINFOCHANGE, // Jack Info Changes
- KSEVENT_TYPE_ENABLE | KSEVENT_TYPE_BASICSUPPORT,
- CMiniportTopology_EventHandler_JackState
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP_EVENT(AutomationMicHsTopoFilter, MicHsPropertiesTopoFilter, MicHsJackInfoChangeEvent);
-
-//=============================================================================
-static
-PCFILTER_DESCRIPTOR MicHsTopoMiniportFilterDescriptor =
-{
- 0, // Version
- &AutomationMicHsTopoFilter, // AutomationTable
- sizeof(PCPIN_DESCRIPTOR), // PinSize
- SIZEOF_ARRAY(MicHsTopoMiniportPins), // PinCount
- MicHsTopoMiniportPins, // Pins
- sizeof(PCNODE_DESCRIPTOR), // NodeSize
- SIZEOF_ARRAY(MicHsTopologyNodes), // NodeCount
- MicHsTopologyNodes, // Nodes
- SIZEOF_ARRAY(MicHsMiniportConnections), // ConnectionCount
- MicHsMiniportConnections, // Connections
- 0, // CategoryCount
- NULL // Categories
-};
-
-#endif // _SYSVAD_MICHSTOPTABLE_H_
-
diff --git a/audio/sysvad/PhoneAudioSample/michswavtable.h b/audio/sysvad/PhoneAudioSample/michswavtable.h
deleted file mode 100644
index 4bfa66db..00000000
--- a/audio/sysvad/PhoneAudioSample/michswavtable.h
+++ /dev/null
@@ -1,447 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- michswavtable.h
-
-Abstract:
-
- Declaration of wave miniport tables for the mic (external: headset).
-
---*/
-
-#ifndef _SYSVAD_MICHSWAVTABLE_H_
-#define _SYSVAD_MICHSWAVTABLE_H_
-
-//
-// Mic in (external: headset) range.
-//
-#define MICHS_DEVICE_MAX_CHANNELS 1 // Max Channels.
-#define MICHS_MIN_BITS_PER_SAMPLE_PCM 16 // Min Bits Per Sample
-#define MICHS_MAX_BITS_PER_SAMPLE_PCM 16 // Max Bits Per Sample
-#define MICHS_MIN_SAMPLE_RATE 8000 // Min Sample Rate
-#define MICHS_MAX_SAMPLE_RATE 48000 // Max Sample Rate
-
-//
-// Max # of pin instances.
-//
-#define MICHS_MAX_INPUT_STREAMS 4
-
-//=============================================================================
-static
-KSDATAFORMAT_WAVEFORMATEXTENSIBLE MicHsPinSupportedDeviceFormats[] =
-{
- { // 0
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 1,
- 8000,
- 16000,
- 2,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_MONO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 1
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 1,
- 11025,
- 22050,
- 2,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_MONO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 2
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 1,
- 16000,
- 32000,
- 2,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_MONO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 3
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 1,
- 22050,
- 44100,
- 2,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_MONO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 4
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 1,
- 24000,
- 48000,
- 2,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_MONO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 5
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 1,
- 32000,
- 64000,
- 2,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_MONO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 6
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 1,
- 44100,
- 88200,
- 2,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_MONO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 7
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 1,
- 48000,
- 96000,
- 2,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_MONO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- }
-};
-
-//
-// Supported modes (only on streaming pins).
-//
-static
-MODE_AND_DEFAULT_FORMAT MicHsPinSupportedDeviceModes[] =
-{
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_RAW,
- &MicHsPinSupportedDeviceFormats[SIZEOF_ARRAY(MicHsPinSupportedDeviceFormats) - 1].DataFormat, // 48KHz
- },
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_DEFAULT,
- &MicHsPinSupportedDeviceFormats[SIZEOF_ARRAY(MicHsPinSupportedDeviceFormats) - 1].DataFormat, // 48KHz
- },
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_SPEECH,
- &MicHsPinSupportedDeviceFormats[2].DataFormat, // 16KHz
- },
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_COMMUNICATIONS,
- &MicHsPinSupportedDeviceFormats[4].DataFormat, // 24KHz
- }
-};
-
-//
-// The entries here must follow the same order as the filter's pin
-// descriptor array.
-//
-static
-PIN_DEVICE_FORMATS_AND_MODES MicHsPinDeviceFormatsAndModes[] =
-{
- {
- BridgePin,
- NULL,
- 0,
- NULL,
- 0
- },
- {
- SystemCapturePin,
- MicHsPinSupportedDeviceFormats,
- SIZEOF_ARRAY(MicHsPinSupportedDeviceFormats),
- MicHsPinSupportedDeviceModes,
- SIZEOF_ARRAY(MicHsPinSupportedDeviceModes)
- }
-};
-
-//=============================================================================
-static
-KSDATARANGE_AUDIO MicHsPinDataRangesStream[] =
-{
- {
- {
- sizeof(KSDATARANGE_AUDIO),
- KSDATARANGE_ATTRIBUTES, // An attributes list follows this data range
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- MICHS_DEVICE_MAX_CHANNELS,
- MICHS_MIN_BITS_PER_SAMPLE_PCM,
- MICHS_MAX_BITS_PER_SAMPLE_PCM,
- MICHS_MIN_SAMPLE_RATE,
- MICHS_MAX_SAMPLE_RATE
- },
-};
-
-static
-PKSDATARANGE MicHsPinDataRangePointersStream[] =
-{
- PKSDATARANGE(&MicHsPinDataRangesStream[0]),
- PKSDATARANGE(&PinDataRangeAttributeList),
-};
-
-//=============================================================================
-static
-KSDATARANGE MicHsPinDataRangesBridge[] =
-{
- {
- sizeof(KSDATARANGE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
- }
-};
-
-static
-PKSDATARANGE MicHsPinDataRangePointersBridge[] =
-{
- &MicHsPinDataRangesBridge[0]
-};
-
-//=============================================================================
-static
-PCPIN_DESCRIPTOR MicHsWaveMiniportPins[] =
-{
- // Wave In Bridge Pin (Capture - From Topology) KSPIN_WAVE_BRIDGE
- {
- 0,
- 0,
- 0,
- NULL,
- {
- 0,
- NULL,
- 0,
- NULL,
- SIZEOF_ARRAY(MicHsPinDataRangePointersBridge),
- MicHsPinDataRangePointersBridge,
- KSPIN_DATAFLOW_IN,
- KSPIN_COMMUNICATION_NONE,
- &KSCATEGORY_AUDIO,
- NULL,
- 0
- }
- },
-
- // Wave In Streaming Pin (Capture) KSPIN_WAVEIN_HOST
- {
- MICHS_MAX_INPUT_STREAMS,
- MICHS_MAX_INPUT_STREAMS,
- 0,
- NULL,
- {
- 0,
- NULL,
- 0,
- NULL,
- SIZEOF_ARRAY(MicHsPinDataRangePointersStream),
- MicHsPinDataRangePointersStream,
- KSPIN_DATAFLOW_OUT,
- KSPIN_COMMUNICATION_SINK,
- &KSCATEGORY_AUDIO,
- &KSAUDFNAME_RECORDING_CONTROL,
- 0
- }
- }
-};
-
-//=============================================================================
-static
-PCNODE_DESCRIPTOR MicHsWaveMiniportNodes[] =
-{
- // KSNODE_WAVE_ADC
- {
- 0, // Flags
- NULL, // AutomationTable
- &KSNODETYPE_ADC, // Type
- NULL // Name
- }
-};
-
-//=============================================================================
-static
-PCCONNECTION_DESCRIPTOR MicHsWaveMiniportConnections[] =
-{
- { PCFILTER_NODE, KSPIN_WAVE_BRIDGE, KSNODE_WAVE_ADC, 1 },
- { KSNODE_WAVE_ADC, 0, PCFILTER_NODE, KSPIN_WAVEIN_HOST }
-};
-
-//=============================================================================
-static
-PCPROPERTY_ITEM PropertiesMicHsWaveFilter[] =
-{
- {
- &KSPROPSETID_General,
- KSPROPERTY_GENERAL_COMPONENTID,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_WaveFilter
- },
- {
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_PROPOSEDATAFORMAT,
- KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_WaveFilter
- },
- {
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_PROPOSEDATAFORMAT2,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_WaveFilter
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationMicHsWaveFilter, PropertiesMicHsWaveFilter);
-
-//=============================================================================
-static
-PCFILTER_DESCRIPTOR MicHsWaveMiniportFilterDescriptor =
-{
- 0, // Version
- &AutomationMicHsWaveFilter, // AutomationTable
- sizeof(PCPIN_DESCRIPTOR), // PinSize
- SIZEOF_ARRAY(MicHsWaveMiniportPins), // PinCount
- MicHsWaveMiniportPins, // Pins
- sizeof(PCNODE_DESCRIPTOR), // NodeSize
- SIZEOF_ARRAY(MicHsWaveMiniportNodes), // NodeCount
- MicHsWaveMiniportNodes, // Nodes
- SIZEOF_ARRAY(MicHsWaveMiniportConnections), // ConnectionCount
- MicHsWaveMiniportConnections, // Connections
- 0, // CategoryCount
- NULL // Categories - use defaults (audio, render, capture)
-};
-
-#endif // _SYSVAD_MICHSWAVTABLE_H_
diff --git a/audio/sysvad/PhoneAudioSample/minipairs.h b/audio/sysvad/PhoneAudioSample/minipairs.h
deleted file mode 100644
index 6b219462..00000000
--- a/audio/sysvad/PhoneAudioSample/minipairs.h
+++ /dev/null
@@ -1,602 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- minipairs.h
-
-Abstract:
-
- Local audio endpoint filter definitions.
-
---*/
-
-#ifndef _SYSVAD_MINIPAIRS_H_
-#define _SYSVAD_MINIPAIRS_H_
-
-#include "speakertopo.h"
-#include "speakertoptable.h"
-#include "speakerwavtable.h"
-
-#include "speakerhstopo.h"
-#include "speakerhstoptable.h"
-#include "speakerhswavtable.h"
-
-#include "michstopo.h"
-#include "michstoptable.h"
-#include "michswavtable.h"
-
-#include "micarraytopo.h"
-#include "micarray1toptable.h"
-#include "micarraywavtable.h"
-
-#include "cellulartopo.h"
-#include "cellularwave.h"
-#include "cellulartoptable.h"
-#include "cellularwavtable.h"
-
-#include "fmtopo.h"
-#include "fmwave.h"
-#include "fmtoptable.h"
-#include "fmwavtable.h"
-
-#include "handsetspeakertopo.h"
-#include "handsetspeakertoptable.h"
-#include "handsetspeakerwavtable.h"
-
-#include "handsetmictopo.h"
-#include "handsetmictoptable.h"
-#include "handsetmicwavtable.h"
-
-
-NTSTATUS
-CreateMiniportWaveRTSYSVAD
-(
- _Out_ PUNKNOWN *,
- _In_ REFCLSID,
- _In_opt_ PUNKNOWN,
- _In_ POOL_TYPE,
- _In_ PUNKNOWN,
- _In_opt_ PVOID,
- _In_ PENDPOINT_MINIPAIR
-);
-
-NTSTATUS
-CreateMiniportTopologySYSVAD
-(
- _Out_ PUNKNOWN *,
- _In_ REFCLSID,
- _In_opt_ PUNKNOWN,
- _In_ POOL_TYPE,
- _In_ PUNKNOWN,
- _In_opt_ PVOID,
- _In_ PENDPOINT_MINIPAIR
-);
-
-//
-// Describe buffer size constraints for WaveRT buffers
-//
-static struct
-{
- KSAUDIO_PACKETSIZE_CONSTRAINTS2 TransportPacketConstraints;
- KSAUDIO_PACKETSIZE_PROCESSINGMODE_CONSTRAINT AdditionalProcessingConstraints[1];
-} SysvadWaveRtPacketSizeConstraintsRender =
-{
- {
- 2 * HNSTIME_PER_MILLISECOND, // 2 ms minimum processing interval
- FILE_BYTE_ALIGNMENT, // 1 byte packet size alignment
- 0, // no maximum packet size constraint
- 2, // 2 processing constraints follow
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_DEFAULT, // constraint for default processing mode
- 128, // 128 samples per processing frame
- 0, // NA hns per processing frame
- },
- },
- {
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_MOVIE, // constraint for movie processing mode
- 1024, // 1024 samples per processing frame
- 0, // NA hns per processing frame
- },
- }
-};
-
-const SYSVAD_DEVPROPERTY SysvadWaveFilterInterfacePropertiesRender[] =
-{
- {
- &DEVPKEY_KsAudio_PacketSize_Constraints2, // Key
- DEVPROP_TYPE_BINARY, // Type
- sizeof(SysvadWaveRtPacketSizeConstraintsRender), // BufferSize
- &SysvadWaveRtPacketSizeConstraintsRender, // Buffer
- },
-};
-
-static struct
-{
- KSAUDIO_PACKETSIZE_CONSTRAINTS2 TransportPacketConstraints;
-} SysvadWaveRtPacketSizeConstraintsCapture =
-{
- {
- 2 * HNSTIME_PER_MILLISECOND, // 2 ms minimum processing interval
- FILE_BYTE_ALIGNMENT, // 1 byte packet size alignment
- 0x100000, // 1 MB maximum packet size
- 1, // 1 processing constraint follows
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_COMMUNICATIONS, // constraint for communications processing mode
- 0, // NA samples per processing frame
- 20 * HNSTIME_PER_MILLISECOND, // 200000 hns (20ms) per processing frame
- },
- },
-};
-
-const SYSVAD_DEVPROPERTY SysvadWaveFilterInterfacePropertiesCapture[] =
-{
- {
- &DEVPKEY_KsAudio_PacketSize_Constraints2, // Key
- DEVPROP_TYPE_BINARY, // Type
- sizeof(SysvadWaveRtPacketSizeConstraintsCapture), // BufferSize
- &SysvadWaveRtPacketSizeConstraintsCapture, // Buffer
- },
-};
-
-//
-// Render miniports.
-//
-
-/*********************************************************************
-* Topology/Wave bridge connection for speaker (internal) *
-* *
-* +------+ +------+ *
-* | Wave | | Topo | *
-* | | | | *
-* System --->|0 2|---> Loopback | | *
-* | | | | *
-* Offload --->|1 3|--------------->|0 1|---> Line Out *
-* | | | | *
-* +------+ +------+ *
-*********************************************************************/
-static
-PHYSICALCONNECTIONTABLE SpeakerTopologyPhysicalConnections[] =
-{
- {
- KSPIN_TOPO_WAVEOUT_SOURCE, // TopologyIn
- KSPIN_WAVE_RENDER_SOURCE, // WaveOut
- CONNECTIONTYPE_WAVE_OUTPUT
- }
-};
-
-static
-ENDPOINT_MINIPAIR SpeakerMiniports =
-{
- eSpeakerDevice,
- SPEAKER_TOPONAME, // defined in cellulartopo.h for use with cellular routing control
- NULL, // optional template name
- CreateMiniportTopologySYSVAD,
- &SpeakerTopoMiniportFilterDescriptor,
- 0, NULL, // Interface properties
- L"WaveSpeaker", // make sure this or the template name matches with KSNAME_WaveSpeaker in the inf's [Strings] section
- NULL, // optional template name
- CreateMiniportWaveRTSYSVAD,
- &SpeakerWaveMiniportFilterDescriptor,
- ARRAYSIZE(SysvadWaveFilterInterfacePropertiesRender), // Interface properties
- SysvadWaveFilterInterfacePropertiesRender,
- SPEAKER_DEVICE_MAX_CHANNELS,
- SpeakerPinDeviceFormatsAndModes,
- SIZEOF_ARRAY(SpeakerPinDeviceFormatsAndModes),
- SpeakerTopologyPhysicalConnections,
- SIZEOF_ARRAY(SpeakerTopologyPhysicalConnections),
- ENDPOINT_OFFLOAD_SUPPORTED,
- SpeakerModulesWaveFilter,
- SIZEOF_ARRAY(SpeakerModulesWaveFilter),
- &SpeakerModuleNotificationDeviceId,
-};
-
-/*********************************************************************
-* Topology/Wave bridge connection for speaker (external:headset) *
-* *
-* +------+ +------+ *
-* | Wave | | Topo | *
-* | | | | *
-* System --->|0 2|---> Loopback | | *
-* | | | | *
-* Offload --->|1 3|--------------->|0 1|---> Line Out *
-* | | | | *
-* +------+ +------+ *
-*********************************************************************/
-static
-PHYSICALCONNECTIONTABLE SpeakerHsTopologyPhysicalConnections[] =
-{
- {
- KSPIN_TOPO_WAVEOUT_SOURCE, // TopologyIn
- KSPIN_WAVE_RENDER_SOURCE, // WaveOut
- CONNECTIONTYPE_WAVE_OUTPUT
- }
-};
-
-static
-ENDPOINT_MINIPAIR SpeakerHsMiniports =
-{
- eSpeakerHsDevice,
- SPEAKER_HEADSET_TOPONAME, // defined in cellulartopo.h for use with cellular routing control
- NULL, // optional template name
- CreateMiniportTopologySYSVAD,
- &SpeakerHsTopoMiniportFilterDescriptor, // use the speaker headset topo filter descriptor, not headset.
- 0, NULL, // Interface properties
- L"WaveSpeakerHeadset", // make sure this or the template name matches with KSNAME_WaveSpeakerHeadset in the inf's [Strings] section
- NULL, // optional template name
- CreateMiniportWaveRTSYSVAD,
- &SpeakerHsWaveMiniportFilterDescriptor,
- 0, NULL, // Interface properties
- SPEAKERHS_DEVICE_MAX_CHANNELS,
- SpeakerHsPinDeviceFormatsAndModes,
- SIZEOF_ARRAY(SpeakerHsPinDeviceFormatsAndModes),
- SpeakerHsTopologyPhysicalConnections,
- SIZEOF_ARRAY(SpeakerHsTopologyPhysicalConnections),
- ENDPOINT_OFFLOAD_SUPPORTED,
- NULL, 0, NULL, // audio module settings.
-};
-
-//
-// headset microphone miniports.
-//
-
-/*********************************************************************
-* Topology/Wave bridge connection for mic in *
-* *
-* +------+ +------+ *
-* | Topo | | Wave | *
-* | | | | *
-* Mic in --->|0 1|===>|0 1|---> Capture Host Pin *
-* | | | | *
-* +------+ +------+ *
-*********************************************************************/
-static
-PHYSICALCONNECTIONTABLE MicHsTopologyPhysicalConnections[] =
-{
- {
- KSPIN_TOPO_BRIDGE, // TopologyOut
- KSPIN_WAVE_BRIDGE, // WaveIn
- CONNECTIONTYPE_TOPOLOGY_OUTPUT
- }
-};
-
-static
-ENDPOINT_MINIPAIR MicHsMiniports =
-{
- eMicHsDevice,
- MIC_HEADSET_TOPONAME, // defined in cellulartopo.h for use with cellular routing control
- NULL, // optional template name
- CreateMiniportTopologySYSVAD,
- &MicHsTopoMiniportFilterDescriptor,
- 0, NULL, // Interface properties
- L"WaveMicHeadset", // make sure this or the template name matches with KSNAME_WaveMicHeadset in the inf's [Strings] section
- NULL, // optional template name
- CreateMiniportWaveRTSYSVAD,
- &MicHsWaveMiniportFilterDescriptor,
- 0, NULL, // Interface properties
- MICHS_DEVICE_MAX_CHANNELS,
- MicHsPinDeviceFormatsAndModes,
- SIZEOF_ARRAY(MicHsPinDeviceFormatsAndModes),
- MicHsTopologyPhysicalConnections,
- SIZEOF_ARRAY(MicHsTopologyPhysicalConnections),
- ENDPOINT_NO_FLAGS,
- NULL, 0, NULL, // audio module settings.
-};
-
-
-//
-// Capture miniports.
-//
-
-/*********************************************************************
-* Topology/Wave bridge connection for mic array 1 (front) *
-* *
-* +------+ +------+ *
-* | Topo | | Wave | *
-* | | | | *
-* Mic in --->|0 1|===>|0 1|---> Capture Host Pin *
-* | | | | *
-* +------+ +------+ *
-*********************************************************************/
-static
-PHYSICALCONNECTIONTABLE MicArray1TopologyPhysicalConnections[] =
-{
- {
- KSPIN_TOPO_BRIDGE, // TopologyOut
- KSPIN_WAVE_BRIDGE, // WaveIn
- CONNECTIONTYPE_TOPOLOGY_OUTPUT
- }
-};
-
-static
-ENDPOINT_MINIPAIR MicArray1Miniports =
-{
- eMicArrayDevice1,
- L"TopologyMicArray1", // make sure this or the template name matches with KSNAME_TopologyMicArray1 in the inf's [Strings] section
- NULL, // optional template name
- CreateMicArrayMiniportTopology,
- &MicArray1TopoMiniportFilterDescriptor,
- 0, NULL, // Interface properties
- L"WaveMicArray1", // make sure this or the tempalte name matches with KSNAME_WaveMicArray1 in the inf's [Strings] section
- NULL, // optional template name
- CreateMiniportWaveRTSYSVAD,
- &MicArrayWaveMiniportFilterDescriptor,
- ARRAYSIZE(SysvadWaveFilterInterfacePropertiesCapture), // Interface properties
- SysvadWaveFilterInterfacePropertiesCapture,
- MICARRAY_DEVICE_MAX_CHANNELS,
- MicArrayPinDeviceFormatsAndModes,
- SIZEOF_ARRAY(MicArrayPinDeviceFormatsAndModes),
- MicArray1TopologyPhysicalConnections,
- SIZEOF_ARRAY(MicArray1TopologyPhysicalConnections),
- ENDPOINT_SOUNDDETECTOR_SUPPORTED,
- NULL, 0, NULL, // audio module settings.
-};
-
-/*********************************************************************
-* Topology/Wave bridge connection for cellular endpoint *
-* *
-* +------+ +------+ *
-* | Wave1| | Topo | *
-* | | | | *
-* | | | | *
-* | | | | *
-* System BiDi <--|0 1|<---------------|1 0|<-- BIDI *
-* | | | | *
-* +------+ | | *
-* | | *
-* +------+ | | *
-* | Wave2| | | *
-* | | | | *
-* | | | | *
-* | | | | *
-* System BiDi <--|0 1|<---------------|3 2|<-- BIDI *
-* | | | | *
-* +------+ +------+ *
-* *
-*********************************************************************/
-
-static
-PHYSICALCONNECTIONTABLE CellularTopologyPhysicalConnections[] =
-{
- {
- KSPIN_TOPO_BIDI1_BRIDGE, // TopologyOut
- KSPIN_WAVE_BIDI_BRIDGE, // WaveIn
- CONNECTIONTYPE_TOPOLOGY_OUTPUT
- }
-};
-
-static
-ENDPOINT_MINIPAIR CellularMiniports =
-{
- eCellularDevice,
- L"TopologyCellular", // make sure this or the template name matches with KSNAME_TopologyCellular in the inf's [Strings] section
- NULL, // optional template name
- CreateCellularMiniportTopology,
- &CellularTopoMiniportFilterDescriptor,
- 0, NULL, // Interface properties
- L"WaveCellular", // make sure this or the template name matches with KSNAME_WaveCellular in the inf's [Strings] section
- NULL, // optional template name
- CreateCellularMiniportWaveRT,
- &CellularWaveMiniportFilterDescriptor,
- 0, NULL, // Interface properties
- CELLULAR_DEVICE_MAX_CHANNELS,
- CellularPinDeviceFormatsAndModes,
- SIZEOF_ARRAY(CellularPinDeviceFormatsAndModes),
- CellularTopologyPhysicalConnections,
- SIZEOF_ARRAY(CellularTopologyPhysicalConnections),
- ENDPOINT_CELLULAR_PROVIDER1,
- NULL, 0, NULL, // audio module settings.
-};
-
-
-static
-PHYSICALCONNECTIONTABLE CellularTopologyPhysicalConnections2[] =
-{
- {
- KSPIN_TOPO_BIDI2_BRIDGE, // TopologyOut
- KSPIN_WAVE_BIDI_BRIDGE, // WaveIn
- CONNECTIONTYPE_TOPOLOGY_OUTPUT
- }
-};
-
-static
-ENDPOINT_MINIPAIR CellularMiniports2 =
-{
- eCellularDevice,
- L"TopologyCellular", // make sure this or the template name matches with KSNAME_TopologyCellular in the inf's [Strings] section
- NULL, // optional template name
- CreateCellularMiniportTopology,
- &CellularTopoMiniportFilterDescriptor,
- 0, NULL, // Interface properties
- L"WaveCellular2", // make sure this or the template name matches with KSNAME_WaveCellular in the inf's [Strings] section
- NULL, // optional template name
- CreateCellularMiniportWaveRT,
- &CellularWaveMiniportFilterDescriptor,
- 0, NULL, // Interface properties
- CELLULAR_DEVICE_MAX_CHANNELS,
- CellularPinDeviceFormatsAndModes,
- SIZEOF_ARRAY(CellularPinDeviceFormatsAndModes),
- CellularTopologyPhysicalConnections2,
- SIZEOF_ARRAY(CellularTopologyPhysicalConnections2),
- ENDPOINT_CELLULAR_PROVIDER2,
- NULL, 0, NULL, // audio module settings.
-};
-
-/*********************************************************************
-* Topology/Wave bridge connection for handset speaker endpoint *
-* *
-* +------+ +------+ *
-* | Wave | | Topo | *
-* | | | | *
-* System --->|0 1|---> Loopback | | *
-* | | | | *
-* | 2|--------------->|0 1|---> Line Out *
-* | | | | *
-* +------+ +------+ *
-*********************************************************************/
-static
-PHYSICALCONNECTIONTABLE HandsetSpeakerTopologyPhysicalConnections[] =
-{
- {
- KSPIN_TOPO_WAVEOUT_SOURCE, // TopologyIn
- KSPIN_WAVE_RENDER2_SOURCE, // WaveOut (no offloading)
- CONNECTIONTYPE_WAVE_OUTPUT
- }
-};
-
-static
-ENDPOINT_MINIPAIR HandsetSpeakerMiniports =
-{
- eHandsetSpeakerDevice,
- HANDSET_SPEAKER_TOPONAME, // defined in cellulartopo.h for use with cellular routing control
- NULL, // optional template name
- CreateHandsetSpeakerMiniportTopology,
- &HandsetSpeakerTopoMiniportFilterDescriptor,
- 0, NULL, // Interface properties
- L"WaveHandsetSpeaker", // make sure this or the template name matches with KSNAME_WaveHandsetSpeaker in the inf's [Strings] section
- NULL, // optional template name
- CreateMiniportWaveRTSYSVAD,
- &HandsetSpeakerWaveMiniportFilterDescriptor,
- 0, NULL, // Interface properties
- HANDSETSPEAKER_DEVICE_MAX_CHANNELS,
- HandsetSpeakerPinDeviceFormatsAndModes,
- SIZEOF_ARRAY(HandsetSpeakerPinDeviceFormatsAndModes),
- HandsetSpeakerTopologyPhysicalConnections,
- SIZEOF_ARRAY(HandsetSpeakerTopologyPhysicalConnections),
- ENDPOINT_LOOPBACK_SUPPORTED,
- NULL, 0, NULL, // audio module settings.
-};
-
-//
-// handset microphone miniports.
-//
-
-/*********************************************************************
-* Topology/Wave bridge connection for mic in *
-* *
-* +------+ +------+ *
-* | Topo | | Wave | *
-* | | | | *
-* Mic in --->|0 1|===>|0 1|---> Capture Host Pin *
-* | | | | *
-* +------+ +------+ *
-*********************************************************************/
-static
-PHYSICALCONNECTIONTABLE HandsetMicTopologyPhysicalConnections[] =
-{
- {
- KSPIN_TOPO_BRIDGE, // TopologyOut
- KSPIN_WAVE_BRIDGE, // WaveIn
- CONNECTIONTYPE_TOPOLOGY_OUTPUT
- }
-};
-
-static
-ENDPOINT_MINIPAIR HandsetMicMiniports =
-{
- eHandsetMicDevice,
- HANDSET_MIC_TOPONAME, // defined in cellulartopo.h for use with cellular routing control
- NULL, // optional template name
- CreateMiniportTopologySYSVAD,
- &HandsetMicTopoMiniportFilterDescriptor,
- 0, NULL, // Interface properties
- L"WaveHandsetMic", // make sure this or the template name matches with KSNAME_WaveHandsetMic in the inf's [Strings] section
- NULL, // optional template name
- CreateMiniportWaveRTSYSVAD,
- &HandsetMicWaveMiniportFilterDescriptor,
- 0, NULL, // Interface properties
- HANDSETMIC_DEVICE_MAX_CHANNELS,
- HandsetMicPinDeviceFormatsAndModes,
- SIZEOF_ARRAY(HandsetMicPinDeviceFormatsAndModes),
- HandsetMicTopologyPhysicalConnections,
- SIZEOF_ARRAY(HandsetMicTopologyPhysicalConnections),
- ENDPOINT_NO_FLAGS,
- NULL, 0, NULL, // audio module settings.
-};
-
-/*********************************************************************
-* Topology/Wave bridge connection for FM RX *
-* *
-* +------+ +------+ *
-* | Topo | | Wave | *
-* | | | | *
-* FM RX --->|0 1|===>|1 0|---> Capture Host Pin *
-* | | | | *
-* +------+ +------+ *
-*********************************************************************/
-static
-PHYSICALCONNECTIONTABLE FmRxTopologyPhysicalConnections[] =
-{
- {
- KSPIN_TOPO_FMRX_BRIDGE, // TopologyOut
- KSPIN_WAVE_FMRX_BRIDGE, // WaveIn
- CONNECTIONTYPE_TOPOLOGY_OUTPUT
- }
-};
-
-static
-ENDPOINT_MINIPAIR FmRxMiniports =
-{
- eFmRxDevice,
- L"TopologyFmRx", // make sure this name matches with KSNAME_TopologyFmRx
- NULL, // optional template name
- CreateFmMiniportTopology,
- &FmTopoMiniportFilterDescriptor,
- 0, NULL, // Interface properties
- L"WaveFmRx", // make sure this or the template name matches with KSNAME_WaveFmRx in the inf's [Strings] section
- NULL, // optional template name
- CreateFmMiniportWaveRT,
- &FmWaveMiniportFilterDescriptor,
- 0, NULL, // Interface properties
- FMRX_DEVICE_MAX_CHANNELS,
- FmRxPinDeviceFormatsAndModes,
- SIZEOF_ARRAY(FmRxPinDeviceFormatsAndModes),
- FmRxTopologyPhysicalConnections,
- SIZEOF_ARRAY(FmRxTopologyPhysicalConnections),
- ENDPOINT_NO_FLAGS,
- NULL, 0, NULL, // audio module settings.
-};
-
-//=============================================================================
-//
-// Render miniport pairs. NOTE: the split of render and capture is arbitrary and
-// unnessary, this array could contain capture endpoints.
-//
-static
-PENDPOINT_MINIPAIR g_RenderEndpoints[] =
-{
- &SpeakerMiniports,
- &SpeakerHsMiniports,
- &HandsetSpeakerMiniports,
- &CellularMiniports, // SIM 1
- &CellularMiniports2 // SIM 2
-};
-
-#define g_cRenderEndpoints (SIZEOF_ARRAY(g_RenderEndpoints))
-
-//=============================================================================
-//
-// Capture miniport pairs. NOTE: the split of render and capture is arbitrary and
-// unnessary, this array could contain render endpoints.
-//
-static
-PENDPOINT_MINIPAIR g_CaptureEndpoints[] =
-{
- &MicHsMiniports,
- &MicArray1Miniports,
- &HandsetMicMiniports,
- &FmRxMiniports
-};
-
-#define g_cCaptureEndpoints (SIZEOF_ARRAY(g_CaptureEndpoints))
-
-//=============================================================================
-//
-// Total miniports = # endpoints * 2 (topology + wave).
-//
-#define g_MaxMiniports ((g_cRenderEndpoints + g_cCaptureEndpoints) * 2)
-
-#endif // _SYSVAD_MINIPAIRS_H_
-
diff --git a/audio/sysvad/PhoneAudioSample/phoneaudiosample.inx b/audio/sysvad/PhoneAudioSample/phoneaudiosample.inx
deleted file mode 100644
index a1d45cf4..00000000
--- a/audio/sysvad/PhoneAudioSample/phoneaudiosample.inx
+++ /dev/null
Binary files differ
diff --git a/audio/sysvad/PhoneAudioSample/speakerhstopo.cpp b/audio/sysvad/PhoneAudioSample/speakerhstopo.cpp
deleted file mode 100644
index bbd7a97c..00000000
--- a/audio/sysvad/PhoneAudioSample/speakerhstopo.cpp
+++ /dev/null
@@ -1,275 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- speakerhstopo.cpp
-
-Abstract:
-
- Implementation of topology miniport for the speaker (external: headset).
-
---*/
-
-#pragma warning (disable : 4127)
-
-#include <sysvad.h>
-#include "simple.h"
-#include "mintopo.h"
-#include "speakerhstopo.h"
-#include "speakerhstoptable.h"
-
-
-#pragma code_seg("PAGE")
-
-//=============================================================================
-NTSTATUS
-PropertyHandler_SpeakerHsJackDescription
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION )
-
-Arguments:
-
- PropertyRequest -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandler_SpeakerHsJackDescription]"));
-
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- ULONG nPinId = (ULONG)-1;
-
- ULONG cJackDescriptions = ARRAYSIZE(SpeakerHsJackDescriptions);
- PKSJACK_DESCRIPTION * JackDescriptions = SpeakerHsJackDescriptions;
-
- if (PropertyRequest->InstanceSize >= sizeof(ULONG))
- {
- nPinId = *(PULONG(PropertyRequest->Instance));
-
- if ((nPinId < cJackDescriptions) && (JackDescriptions[nPinId] != NULL))
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ntStatus =
- PropertyHandler_BasicSupport
- (
- PropertyRequest,
- KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
- VT_ILLEGAL
- );
- }
- else
- {
- ULONG cbNeeded = sizeof(KSMULTIPLE_ITEM) + sizeof(KSJACK_DESCRIPTION);
-
- if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = cbNeeded;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else if (PropertyRequest->ValueSize < cbNeeded)
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- PKSMULTIPLE_ITEM pMI = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
- PKSJACK_DESCRIPTION pDesc = (PKSJACK_DESCRIPTION)(pMI+1);
-
- pMI->Size = cbNeeded;
- pMI->Count = 1;
-
- RtlCopyMemory(pDesc, JackDescriptions[nPinId], sizeof(KSJACK_DESCRIPTION));
- ntStatus = STATUS_SUCCESS;
- }
- }
- }
- }
- }
-
- return ntStatus;
-}
-
-//=============================================================================
-NTSTATUS
-PropertyHandler_SpeakerHsJackDescription2
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION2 )
-
-Arguments:
-
- PropertyRequest -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandler_SpeakerHsJackDescription2]"));
-
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
- ULONG nPinId = (ULONG)-1;
-
- ULONG cJackDescriptions = ARRAYSIZE(SpeakerHsJackDescriptions);
- PKSJACK_DESCRIPTION * JackDescriptions = SpeakerHsJackDescriptions;
-
- if (PropertyRequest->InstanceSize >= sizeof(ULONG))
- {
- nPinId = *(PULONG(PropertyRequest->Instance));
-
- if ((nPinId < cJackDescriptions) && (JackDescriptions[nPinId] != NULL))
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
- {
- ntStatus =
- PropertyHandler_BasicSupport
- (
- PropertyRequest,
- KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
- VT_ILLEGAL
- );
- }
- else
- {
- ULONG cbNeeded = sizeof(KSMULTIPLE_ITEM) + sizeof(KSJACK_DESCRIPTION2);
-
- if (PropertyRequest->ValueSize == 0)
- {
- PropertyRequest->ValueSize = cbNeeded;
- ntStatus = STATUS_BUFFER_OVERFLOW;
- }
- else if (PropertyRequest->ValueSize < cbNeeded)
- {
- ntStatus = STATUS_BUFFER_TOO_SMALL;
- }
- else
- {
- if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
- {
- PKSMULTIPLE_ITEM pMI = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
- PKSJACK_DESCRIPTION2 pDesc = (PKSJACK_DESCRIPTION2)(pMI+1);
-
- pMI->Size = cbNeeded;
- pMI->Count = 1;
-
- RtlZeroMemory(pDesc, sizeof(KSJACK_DESCRIPTION2));
-
- //
- // Specifies the lower 16 bits of the DWORD parameter. This parameter indicates whether
- // the jack is currently active, streaming, idle, or hardware not ready.
- //
- pDesc->DeviceStateInfo = 0;
-
- //
- // From MSDN:
- // "If an audio device lacks jack presence detection, the IsConnected member of
- // the KSJACK_DESCRIPTION structure must always be set to TRUE. To remove the
- // ambiguity that results from this dual meaning of the TRUE value for IsConnected,
- // a client application can call IKsJackDescription2::GetJackDescription2 to read
- // the JackCapabilities flag of the KSJACK_DESCRIPTION2 structure. If this flag has
- // the JACKDESC2_PRESENCE_DETECT_CAPABILITY bit set, it indicates that the endpoint
- // does in fact support jack presence detection. In that case, the return value of
- // the IsConnected member can be interpreted to accurately reflect the insertion status
- // of the jack."
- //
- // Bit definitions:
- // 0x00000001 - JACKDESC2_PRESENCE_DETECT_CAPABILITY
- // 0x00000002 - JACKDESC2_DYNAMIC_FORMAT_CHANGE_CAPABILITY
- //
- pDesc->JackCapabilities = JACKDESC2_PRESENCE_DETECT_CAPABILITY;
-
- ntStatus = STATUS_SUCCESS;
- }
- }
- }
- }
- }
-
- return ntStatus;
-}
-
-
-//=============================================================================
-NTSTATUS
-PropertyHandler_SpeakerHsTopoFilter
-(
- _In_ PPCPROPERTY_REQUEST PropertyRequest
-)
-/*++
-
-Routine Description:
-
- Redirects property request to miniport object
-
-Arguments:
-
- PropertyRequest -
-
-Return Value:
-
- NT status code.
-
---*/
-{
- PAGED_CODE();
-
- ASSERT(PropertyRequest);
-
- DPF_ENTER(("[PropertyHandler_SpeakerHsTopoFilter]"));
-
- // PropertryRequest structure is filled by portcls.
- // MajorTarget is a pointer to miniport object for miniports.
- //
- NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
-
- //
- // This line shows how to get a pointer to the miniport topology object.
- //
- PCMiniportTopology pMiniport = (PCMiniportTopology)PropertyRequest->MajorTarget;
- UNREFERENCED_VAR(pMiniport);
-
- if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Jack))
- {
- if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION)
- {
- ntStatus = PropertyHandler_SpeakerHsJackDescription(PropertyRequest);
- }
- else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION2)
- {
- ntStatus = PropertyHandler_SpeakerHsJackDescription2(PropertyRequest);
- }
- }
-
- return ntStatus;
-} // PropertyHandler_SpeakerHsTopoFilter
-
-#pragma code_seg()
-
diff --git a/audio/sysvad/PhoneAudioSample/speakerhstopo.h b/audio/sysvad/PhoneAudioSample/speakerhstopo.h
deleted file mode 100644
index ea7c760f..00000000
--- a/audio/sysvad/PhoneAudioSample/speakerhstopo.h
+++ /dev/null
@@ -1,21 +0,0 @@
-
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- speakerhstopo.h
-
-Abstract:
-
- Declaration of topology miniport for the speaker (external: headset).
-
---*/
-
-#ifndef _SYSVAD_SPEAKERHSTOPO_H_
-#define _SYSVAD_SPEAKERHSTOPO_H_
-
-NTSTATUS PropertyHandler_SpeakerHsTopoFilter(_In_ PPCPROPERTY_REQUEST PropertyRequest);
-
-#endif // _SYSVAD_SPEAKERHSTOPO_H_
diff --git a/audio/sysvad/PhoneAudioSample/speakerhstoptable.h b/audio/sysvad/PhoneAudioSample/speakerhstoptable.h
deleted file mode 100644
index adb941ff..00000000
--- a/audio/sysvad/PhoneAudioSample/speakerhstoptable.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- speakerhstoptable.h
-
-Abstract:
-
- Declaration of topology tables for the speaker (external: headset).
-
---*/
-
-#ifndef _SYSVAD_SPEAKERHSTOPTABLE_H_
-#define _SYSVAD_SPEAKERHSTOPTABLE_H_
-
-#include <mintopo.h>
-
-//=============================================================================
-static
-KSDATARANGE SpeakerHsTopoPinDataRangesBridge[] =
-{
- {
- sizeof(KSDATARANGE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
- }
-};
-
-//=============================================================================
-static
-PKSDATARANGE SpeakerHsTopoPinDataRangePointersBridge[] =
-{
- &SpeakerHsTopoPinDataRangesBridge[0]
-};
-
-//=============================================================================
-static
-PCPIN_DESCRIPTOR SpeakerHsTopoMiniportPins[] =
-{
- // KSPIN - topology filter in-pin
- {
- 0,
- 0,
- 0, // InstanceCount
- NULL, // AutomationTable
- { // KsPinDescriptor
- 0, // InterfacesCount
- NULL, // Interfaces
- 0, // MediumsCount
- NULL, // Mediums
- SIZEOF_ARRAY(SpeakerHsTopoPinDataRangePointersBridge),// DataRangesCount
- SpeakerHsTopoPinDataRangePointersBridge, // DataRanges
- KSPIN_DATAFLOW_IN, // DataFlow
- KSPIN_COMMUNICATION_NONE, // Communication
- &KSCATEGORY_AUDIO, // Category
- NULL, // Name
- 0 // Reserved
- }
- },
- // KSPIN - topology filter out-pin
- {
- 0,
- 0,
- 0, // InstanceCount
- NULL, // AutomationTable
- { // KsPinDescriptor
- 0, // InterfacesCount
- NULL, // Interfaces
- 0, // MediumsCount
- NULL, // Mediums
- SIZEOF_ARRAY(SpeakerHsTopoPinDataRangePointersBridge),// DataRangesCount
- SpeakerHsTopoPinDataRangePointersBridge, // DataRanges
- KSPIN_DATAFLOW_OUT, // DataFlow
- KSPIN_COMMUNICATION_NONE, // Communication
- &KSNODETYPE_HEADSET_SPEAKERS, // Category
- NULL, // Name
- 0 // Reserved
- }
- }
-};
-
-static
-KSJACK_DESCRIPTION SpeakerHsJackDesc =
-{
- KSAUDIO_SPEAKER_MONO,
- JACKDESC_RGB(179, 201, 140),
- eConnTypeCombination,
- eGeoLocRear,
- eGenLocPrimaryBox,
- ePortConnJack,
- FALSE // NOTE: For convenience, wired headset jacks will be "unplugged" at boot.
-};
-
-//=============================================================================
-// Only return a KSJACK_DESCRIPTION for the physical bridge pin.
-static
-PKSJACK_DESCRIPTION SpeakerHsJackDescriptions[] =
-{
- NULL,
- &SpeakerHsJackDesc
-};
-
-//=============================================================================
-static
-PCCONNECTION_DESCRIPTOR SpeakerHsTopoMiniportConnections[] =
-{
- // FromNode, FromPin, ToNode, ToPin
- { PCFILTER_NODE, KSPIN_TOPO_WAVEOUT_SOURCE, PCFILTER_NODE, KSPIN_TOPO_LINEOUT_DEST}
-};
-
-
-//=============================================================================
-static
-PCPROPERTY_ITEM PropertiesSpeakerHsTopoFilter[] =
-{
- {
- &KSPROPSETID_Jack,
- KSPROPERTY_JACK_DESCRIPTION,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_SpeakerHsTopoFilter
- },
- {
- &KSPROPSETID_Jack,
- KSPROPERTY_JACK_DESCRIPTION2,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_SpeakerHsTopoFilter
- }
-};
-
-static PCEVENT_ITEM SpeakerHsJackInfoChangeEvent[] =
-{
- {
- &KSEVENTSETID_PinCapsChange, // Something changed
- KSEVENT_PINCAPS_JACKINFOCHANGE, // Jack Info Changes
- KSEVENT_TYPE_ENABLE | KSEVENT_TYPE_BASICSUPPORT,
- CMiniportTopology_EventHandler_JackState
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP_EVENT(AutomationSpeakerHsTopoFilter, PropertiesSpeakerHsTopoFilter, SpeakerHsJackInfoChangeEvent);
-
-//=============================================================================
-static
-PCFILTER_DESCRIPTOR SpeakerHsTopoMiniportFilterDescriptor =
-{
- 0, // Version
- &AutomationSpeakerHsTopoFilter, // AutomationTable
- sizeof(PCPIN_DESCRIPTOR), // PinSize
- SIZEOF_ARRAY(SpeakerHsTopoMiniportPins), // PinCount
- SpeakerHsTopoMiniportPins, // Pins
- sizeof(PCNODE_DESCRIPTOR), // NodeSize
- 0, // NodeCount
- NULL, // Nodes
- SIZEOF_ARRAY(SpeakerHsTopoMiniportConnections), // ConnectionCount
- SpeakerHsTopoMiniportConnections, // Connections
- 0, // CategoryCount
- NULL // Categories
-};
-
-#endif // _SYSVAD_SPEAKERHSTOPTABLE_H_
-
-
diff --git a/audio/sysvad/PhoneAudioSample/speakerhswavtable.h b/audio/sysvad/PhoneAudioSample/speakerhswavtable.h
deleted file mode 100644
index cc7b55fc..00000000
--- a/audio/sysvad/PhoneAudioSample/speakerhswavtable.h
+++ /dev/null
@@ -1,755 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation All Rights Reserved
-
-Module Name:
-
- speakerhswavtable.h
-
-Abstract:
-
- Declaration of wave miniport tables for the speaker (external: headset).
-
---*/
-
-#ifndef _SYSVAD_SPEAKERHSWAVTABLE_H_
-#define _SYSVAD_SPEAKERHSWAVTABLE_H_
-
-
-// To keep the code simple assume device supports only 48KHz, 16-bit, stereo (PCM and NON-PCM)
-
-#define SPEAKERHS_DEVICE_MAX_CHANNELS 2 // Max Channels.
-
-#define SPEAKERHS_HOST_MAX_CHANNELS 2 // Max Channels.
-#define SPEAKERHS_HOST_MIN_BITS_PER_SAMPLE 16 // Min Bits Per Sample
-#define SPEAKERHS_HOST_MAX_BITS_PER_SAMPLE 16 // Max Bits Per Sample
-#define SPEAKERHS_HOST_MIN_SAMPLE_RATE 24000 // Min Sample Rate
-#define SPEAKERHS_HOST_MAX_SAMPLE_RATE 96000 // Max Sample Rate
-
-#define SPEAKERHS_OFFLOAD_MAX_CHANNELS 2 // Max Channels.
-#define SPEAKERHS_OFFLOAD_MIN_BITS_PER_SAMPLE 16 // Min Bits Per Sample
-#define SPEAKERHS_OFFLOAD_MAX_BITS_PER_SAMPLE 16 // Max Bits Per Sample
-#define SPEAKERHS_OFFLOAD_MIN_SAMPLE_RATE 44100 // Min Sample Rate
-#define SPEAKERHS_OFFLOAD_MAX_SAMPLE_RATE 48000 // Max Sample Rate
-
-#define SPEAKERHS_LOOPBACK_MAX_CHANNELS SPEAKERHS_HOST_MAX_CHANNELS // Must be equal to host pin's Max Channels.
-#define SPEAKERHS_LOOPBACK_MIN_BITS_PER_SAMPLE SPEAKERHS_HOST_MIN_BITS_PER_SAMPLE // Must be equal to host pin's Min Bits Per Sample
-#define SPEAKERHS_LOOPBACK_MAX_BITS_PER_SAMPLE SPEAKERHS_HOST_MAX_BITS_PER_SAMPLE // Must be equal to host pin's Max Bits Per Sample
-#define SPEAKERHS_LOOPBACK_MIN_SAMPLE_RATE SPEAKERHS_HOST_MIN_SAMPLE_RATE // Must be equal to host pin's Min Sample Rate
-#define SPEAKERHS_LOOPBACK_MAX_SAMPLE_RATE SPEAKERHS_HOST_MAX_SAMPLE_RATE // Must be equal to host pin's Max Sample Rate
-
-#define SPEAKERHS_DOLBY_DIGITAL_MAX_CHANNELS 2 // Max Channels.
-#define SPEAKERHS_DOLBY_DIGITAL_MIN_BITS_PER_SAMPLE 16 // Min Bits Per Sample
-#define SPEAKERHS_DOLBY_DIGITAL_MAX_BITS_PER_SAMPLE 16 // Max Bits Per Sample
-#define SPEAKERHS_DOLBY_DIGITAL_MIN_SAMPLE_RATE 44100 // Min Sample Rate
-#define SPEAKERHS_DOLBY_DIGITAL_MAX_SAMPLE_RATE 44100 // Max Sample Rate
-
-//
-// Max # of pin instances.
-//
-#define SPEAKERHS_MAX_INPUT_SYSTEM_STREAMS 6
-#define SPEAKERHS_MAX_INPUT_OFFLOAD_STREAMS MAX_INPUT_OFFLOAD_STREAMS
-#define SPEAKERHS_MAX_OUTPUT_LOOPBACK_STREAMS MAX_OUTPUT_LOOPBACK_STREAMS
-
-//=============================================================================
-static
-KSDATAFORMAT_WAVEFORMATEXTENSIBLE SpeakerHsAudioEngineSupportedDeviceFormats[] =
-{
- { // 0 : First entry in htis table is the default format for the audio engine
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 44100,
- 176400,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 1
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 24000,
- 96000,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 2
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 48000,
- 192000,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 3
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 88200,
- 352800,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 4
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 96000,
- 384000,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- }
-};
-
-static
-KSDATAFORMAT_WAVEFORMATEXTENSIBLE SpeakerHsHostPinSupportedDeviceFormats[] =
-{
- { // 0
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 24000,
- 96000,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 1
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 32000,
- 128000,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 2
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 44100,
- 176400,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 3
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 48000,
- 192000,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 4
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 88200,
- 352800,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 5
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 96000,
- 384000,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- }
-};
-
-static
-KSDATAFORMAT_WAVEFORMATEXTENSIBLE SpeakerHsOffloadPinSupportedDeviceFormats[] =
-{
- { // 0
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 44100,
- 176400,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- },
- { // 1
- {
- sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- {
- {
- WAVE_FORMAT_EXTENSIBLE,
- 2,
- 48000,
- 192000,
- 4,
- 16,
- sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
- },
- 16,
- KSAUDIO_SPEAKER_STEREO,
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
- }
- }
-};
-
-//
-// Supported modes (only on streaming pins).
-//
-static
-MODE_AND_DEFAULT_FORMAT SpeakerHsHostPinSupportedDeviceModes[] =
-{
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_RAW,
- &SpeakerHsHostPinSupportedDeviceFormats[3].DataFormat // 48KHz
- },
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_DEFAULT,
- &SpeakerHsHostPinSupportedDeviceFormats[3].DataFormat // 48KHz
- },
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_MEDIA,
- &SpeakerHsHostPinSupportedDeviceFormats[3].DataFormat // 48KHz
- },
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_MOVIE,
- &SpeakerHsHostPinSupportedDeviceFormats[3].DataFormat // 48KHz
- },
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_COMMUNICATIONS,
- &SpeakerHsHostPinSupportedDeviceFormats[0].DataFormat // 24KHz
- },
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_NOTIFICATION,
- &SpeakerHsHostPinSupportedDeviceFormats[3].DataFormat // 48KHz
- }
-};
-
-static
-MODE_AND_DEFAULT_FORMAT SpeakerHsOffloadPinSupportedDeviceModes[] =
-{
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_DEFAULT,
- &SpeakerHsOffloadPinSupportedDeviceFormats[1].DataFormat // 48KHz
- },
- {
- STATIC_AUDIO_SIGNALPROCESSINGMODE_MEDIA,
- &SpeakerHsOffloadPinSupportedDeviceFormats[1].DataFormat // 48KHz
- }
-};
-
-//
-// The entries here must follow the same order as the filter's pin
-// descriptor array.
-//
-static
-PIN_DEVICE_FORMATS_AND_MODES SpeakerHsPinDeviceFormatsAndModes[] =
-{
- {
- SystemRenderPin,
- SpeakerHsHostPinSupportedDeviceFormats,
- SIZEOF_ARRAY(SpeakerHsHostPinSupportedDeviceFormats),
- SpeakerHsHostPinSupportedDeviceModes,
- SIZEOF_ARRAY(SpeakerHsHostPinSupportedDeviceModes)
- },
- {
- OffloadRenderPin,
- SpeakerHsOffloadPinSupportedDeviceFormats,
- SIZEOF_ARRAY(SpeakerHsOffloadPinSupportedDeviceFormats),
- SpeakerHsOffloadPinSupportedDeviceModes,
- SIZEOF_ARRAY(SpeakerHsOffloadPinSupportedDeviceModes),
- },
- {
- RenderLoopbackPin,
- SpeakerHsHostPinSupportedDeviceFormats, // Must support all the formats supported by host pin
- SIZEOF_ARRAY(SpeakerHsHostPinSupportedDeviceFormats),
- NULL, // loopback doesn't support modes.
- 0
- },
- {
- BridgePin,
- NULL,
- 0,
- NULL,
- 0
- },
- {
- NoPin, // For convenience, offload engine device formats appended here
- SpeakerHsAudioEngineSupportedDeviceFormats,
- SIZEOF_ARRAY(SpeakerHsAudioEngineSupportedDeviceFormats),
- NULL, // no modes for this entry.
- 0
- }
-};
-
-//=============================================================================
-static
-KSDATARANGE_AUDIO SpeakerHsPinDataRangesStream[] =
-{
- { // 0
- {
- sizeof(KSDATARANGE_AUDIO),
- KSDATARANGE_ATTRIBUTES, // An attributes list follows this data range
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- SPEAKERHS_HOST_MAX_CHANNELS,
- SPEAKERHS_HOST_MIN_BITS_PER_SAMPLE,
- SPEAKERHS_HOST_MAX_BITS_PER_SAMPLE,
- SPEAKERHS_HOST_MIN_SAMPLE_RATE,
- SPEAKERHS_HOST_MAX_SAMPLE_RATE
- },
- { // 1
- {
- sizeof(KSDATARANGE_AUDIO),
- KSDATARANGE_ATTRIBUTES, // An attributes list follows this data range
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- SPEAKERHS_OFFLOAD_MAX_CHANNELS,
- SPEAKERHS_OFFLOAD_MIN_BITS_PER_SAMPLE,
- SPEAKERHS_OFFLOAD_MAX_BITS_PER_SAMPLE,
- SPEAKERHS_OFFLOAD_MIN_SAMPLE_RATE,
- SPEAKERHS_OFFLOAD_MAX_SAMPLE_RATE
- },
- { // 2
- {
- sizeof(KSDATARANGE_AUDIO),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
- },
- SPEAKERHS_LOOPBACK_MAX_CHANNELS,
- SPEAKERHS_LOOPBACK_MIN_BITS_PER_SAMPLE,
- SPEAKERHS_LOOPBACK_MAX_BITS_PER_SAMPLE,
- SPEAKERHS_LOOPBACK_MIN_SAMPLE_RATE,
- SPEAKERHS_LOOPBACK_MAX_SAMPLE_RATE
- }
-};
-
-static
-PKSDATARANGE SpeakerHsPinDataRangePointersStream[] =
-{
- PKSDATARANGE(&SpeakerHsPinDataRangesStream[0]),
- PKSDATARANGE(&PinDataRangeAttributeList)
-};
-
-static
-PKSDATARANGE SpeakerHsPinDataRangePointersOffloadStream[] =
-{
- PKSDATARANGE(&SpeakerHsPinDataRangesStream[1]),
- PKSDATARANGE(&PinDataRangeAttributeList)
-};
-
-static
-PKSDATARANGE SpeakerHsPinDataRangePointersLoopbackStream[] =
-{
- PKSDATARANGE(&SpeakerHsPinDataRangesStream[2])
-};
-
-//=============================================================================
-static
-KSDATARANGE SpeakerHsPinDataRangesBridge[] =
-{
- {
- sizeof(KSDATARANGE),
- 0,
- 0,
- 0,
- STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
- STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
- STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
- }
-};
-
-static
-PKSDATARANGE SpeakerHsPinDataRangePointersBridge[] =
-{
- &SpeakerHsPinDataRangesBridge[0]
-};
-
-//=============================================================================
-
-static
-PCPROPERTY_ITEM PropertiesSpeakerHsOffloadPin[] =
-{
- {
- &KSPROPSETID_OffloadPin, // define new property set
- KSPROPERTY_OFFLOAD_PIN_GET_STREAM_OBJECT_POINTER, // define properties
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_OffloadPin
- },
- {
- &KSPROPSETID_OffloadPin, // define new property set
- KSPROPERTY_OFFLOAD_PIN_VERIFY_STREAM_OBJECT_POINTER, // define properties
- KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_OffloadPin
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSpeakerHsOffloadPin, PropertiesSpeakerHsOffloadPin);
-
-//=============================================================================
-static
-PCPIN_DESCRIPTOR SpeakerHsWaveMiniportPins[] =
-{
- // Wave Out Streaming Pin (renderer) KSPIN_WAVE_RENDER_SINK_SYSTEM
- {
- SPEAKERHS_MAX_INPUT_SYSTEM_STREAMS,
- SPEAKERHS_MAX_INPUT_SYSTEM_STREAMS,
- 0,
- NULL,
- {
- 0,
- NULL,
- 0,
- NULL,
- SIZEOF_ARRAY(SpeakerHsPinDataRangePointersStream),
- SpeakerHsPinDataRangePointersStream,
- KSPIN_DATAFLOW_IN,
- KSPIN_COMMUNICATION_SINK,
- &KSCATEGORY_AUDIO,
- NULL,
- 0
- }
- },
- // Wave Out Streaming Pin (Renderer) KSPIN_WAVE_RENDER_SINK_OFFLOAD
- {
- SPEAKERHS_MAX_INPUT_OFFLOAD_STREAMS,
- SPEAKERHS_MAX_INPUT_OFFLOAD_STREAMS,
- 0,
- &AutomationSpeakerHsOffloadPin, // AutomationTable
- {
- 0,
- NULL,
- 0,
- NULL,
- SIZEOF_ARRAY(SpeakerHsPinDataRangePointersOffloadStream),
- SpeakerHsPinDataRangePointersOffloadStream,
- KSPIN_DATAFLOW_IN,
- KSPIN_COMMUNICATION_SINK,
- &KSCATEGORY_AUDIO,
- NULL,
- 0
- }
- },
- // Wave Out Streaming Pin (Renderer) KSPIN_WAVE_RENDER_SINK_LOOPBACK
- {
- SPEAKERHS_MAX_OUTPUT_LOOPBACK_STREAMS,
- SPEAKERHS_MAX_OUTPUT_LOOPBACK_STREAMS,
- 0,
- NULL,
- {
- 0,
- NULL,
- 0,
- NULL,
- SIZEOF_ARRAY(SpeakerHsPinDataRangePointersLoopbackStream),
- SpeakerHsPinDataRangePointersLoopbackStream,
- KSPIN_DATAFLOW_OUT,
- KSPIN_COMMUNICATION_SINK,
- &KSNODETYPE_AUDIO_LOOPBACK,
- NULL,
- 0
- }
- },
- // Wave Out Bridge Pin (Renderer) KSPIN_WAVE_RENDER_SOURCE
- {
- 0,
- 0,
- 0,
- NULL,
- {
- 0,
- NULL,
- 0,
- NULL,
- SIZEOF_ARRAY(SpeakerHsPinDataRangePointersBridge),
- SpeakerHsPinDataRangePointersBridge,
- KSPIN_DATAFLOW_OUT,
- KSPIN_COMMUNICATION_NONE,
- &KSCATEGORY_AUDIO,
- NULL,
- 0
- }
- },
-};
-
-//=============================================================================
-static
-PCNODE_DESCRIPTOR SpeakerHsWaveMiniportNodes[] =
-{
- // KSNODE_WAVE_AUDIO_ENGINE
- {
- 0, // Flags
- NULL, // AutomationTable
- &KSNODETYPE_AUDIO_ENGINE, // Type KSNODETYPE_AUDIO_ENGINE
- NULL // Name
- }
-};
-//=============================================================================
-//
-// ----------------------------
-// | |
-// System Pin 0-->| |--> 2 Loopback Pin
-// | HW Audio Engine node |
-// Offload Pin 1-->| |--> 3 KSPIN_WAVE_RENDER_SOURCE
-// | |
-// ----------------------------
-static
-PCCONNECTION_DESCRIPTOR SpeakerHsWaveMiniportConnections[] =
-{
- { PCFILTER_NODE, KSPIN_WAVE_RENDER_SINK_SYSTEM, KSNODE_WAVE_AUDIO_ENGINE, 1 },
- { PCFILTER_NODE, KSPIN_WAVE_RENDER_SINK_OFFLOAD, KSNODE_WAVE_AUDIO_ENGINE, 2 },
- { KSNODE_WAVE_AUDIO_ENGINE, 3, PCFILTER_NODE, KSPIN_WAVE_RENDER_SINK_LOOPBACK },
- { KSNODE_WAVE_AUDIO_ENGINE, 0, PCFILTER_NODE, KSPIN_WAVE_RENDER_SOURCE },
-};
-
-//=============================================================================
-static
-PCPROPERTY_ITEM PropertiesSpeakerHsWaveFilter[] =
-{
- {
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_PROPOSEDATAFORMAT,
- KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_WaveFilter
- },
- {
- &KSPROPSETID_Pin,
- KSPROPERTY_PIN_PROPOSEDATAFORMAT2,
- KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
- PropertyHandler_WaveFilter
- }
-};
-
-DEFINE_PCAUTOMATION_TABLE_PROP(AutomationSpeakerHsWaveFilter, PropertiesSpeakerHsWaveFilter);
-
-//=============================================================================
-static
-PCFILTER_DESCRIPTOR SpeakerHsWaveMiniportFilterDescriptor =
-{
- 0, // Version
- &AutomationSpeakerHsWaveFilter, // AutomationTable
- sizeof(PCPIN_DESCRIPTOR), // PinSize
- SIZEOF_ARRAY(SpeakerHsWaveMiniportPins), // PinCount
- SpeakerHsWaveMiniportPins, // Pins
- sizeof(PCNODE_DESCRIPTOR), // NodeSize
- SIZEOF_ARRAY(SpeakerHsWaveMiniportNodes), // NodeCount
- SpeakerHsWaveMiniportNodes, // Nodes
- SIZEOF_ARRAY(SpeakerHsWaveMiniportConnections), // ConnectionCount
- SpeakerHsWaveMiniportConnections, // Connections
- 0, // CategoryCount
- NULL // Categories - use defaults (audio, render, capture)
-};
-
-#endif // _SYSVAD_SPEAKERHSWAVTABLE_H_
-
diff --git a/audio/sysvad/README.md b/audio/sysvad/README.md
index d2c07a22..3a799ba2 100644
--- a/audio/sysvad/README.md
+++ b/audio/sysvad/README.md
@@ -5,67 +5,62 @@ languages:
- cpp
products:
- windows
+- windows-wdk
urlFragment: sysvad-virtual-audio-device-driver-sample
---
-<!---
- name: SysVAD Virtual Audio Device Driver Sample
- platform: WDM
- language: cpp
- category: Audio
- description: The Microsoft SysVAD Virtual Audio Device Driver (SYSVAD) shows how to develop a WDM audio driver that exposes support for multiple audio devices.
- samplefwlink: http://go.microsoft.com/fwlink/p/?LinkId=620183
---->
-
# SysVAD Virtual Audio Device Driver Sample
+## Important note
+
+With the [end of support for Windows 10 Mobile](https://support.microsoft.com/help/4484693/windows-10-mobile-end-of-support), the Phone Audio sample has been also removed from the SysVAD driver sample.
+
+## Introduction
+
The Microsoft SysVAD Virtual Audio Device Driver (SYSVAD) shows how to develop a WDM audio driver that exposes support for multiple audio devices.
Some of these audio devices are embedded in the system (for example, speakers, microphone arrays) while others are pluggable (like headphones, Bluetooth headsets etc.). The driver uses WaveRT and audio offloading for rendering devices. The driver uses a "virtual audio device" instead of an actual hardware-based adapter, and highlights the different aspects of the audio offloading WDM audio driver architecture.
Driver developers can use the framework in this sample to provide support for various audio devices without concern for hardware dependencies. The framework includes implementations of the following interfaces:
-- The CAdapterCommon interface gives the miniports access to virtual mixer hardware. It also implements the **IAdapterPowerManagement** interface.
+- The CAdapterCommon interface gives the miniports access to virtual mixer hardware. It also implements the **IAdapterPowerManagement** interface.
-- The CMiniportTopologySYSVAD interface is the base class for all sample topologies. It has very basic common functions. In addition, this class contains common topology property handlers.
+- The CMiniportTopologySYSVAD interface is the base class for all sample topologies. It has very basic common functions. In addition, this class contains common topology property handlers.
The following table shows the features that are implemented in the various subdirectories of this sample.
-Directory | Description
------|------------
-TabletAudioSample | Endpoints that are present in TabletAudioSample driver.
-PhoneAudioSample | Endpoints that are present in PhoneAudioSample driver.
-EndpointsCommon | Endpoints that are present in both TabletAudioSample and PhoneAudioSample. It also contains other common code shared by both sample drivers.
-SwapAPO | Sample APO that installs onto endpoints exposed by the SysVAD sample driver and swaps the left and right channels.
-DelayAPO | Sample APO that adds a delay to the input samples.
-KwsAPO | Sample APO that uses KSPROPERTY_INTERLEAVEDAUDIO_FORMATINFORMATION to determine if the keyword spotter pin is interleaving loopback audio with the microphone audio and identify which channels contain loopback audio. If it is interleaved the APO will strip out the loopback audio and deliver only the microphone audio upstream. Because channel data is removed, the APO negotiates an output format which is different than the input format.
-KeywordDetectorAdapter | Sample Keyword Detector Adapter.
+| Directory | Description |
+| --- | --- |
+| TabletAudioSample | Endpoints that are present in TabletAudioSample driver. |
+| EndpointsCommon | Endpoints that are present in both TabletAudioSample and PhoneAudioSample. It also contains other common code shared by both sample drivers. |
+| SwapAPO | Sample APO that installs onto endpoints exposed by the SysVAD sample driver and swaps the left and right channels. |
+| DelayAPO | Sample APO that adds a delay to the input samples. |
+| KwsAPO | Sample APO that uses KSPROPERTY_INTERLEAVEDAUDIO_FORMATINFORMATION to determine if the keyword spotter pin is interleaving loopback audio with the microphone audio and identify which channels contain loopback audio. If it is interleaved the APO will strip out the loopback audio and deliver only the microphone audio upstream. Because channel data is removed, the APO negotiates an output format which is different than the input format. |
+| KeywordDetectorAdapter | Sample Keyword Detector Adapter. |
-For more information about the Windows audio engine, see [Exposing Hardware-Offloaded Audio Processing in Windows](http://msdn.microsoft.com/en-us/windows/hardware/br259116), and note that audio hardware that is offload-capable replicates the architecture that is presented in the diagram shown in the topic.
+For more information about the Windows audio engine, see [Hardware-Offloaded Audio Processing](https://docs.microsoft.com/windows-hardware/drivers/audio/hardware-offloaded-audio-processing), and note that audio hardware that is offload-capable replicates the architecture that is presented in the diagram shown in the topic.
+## Build the sample
-Build the sample
-----------------
-
-If you simply want to Build this sample driver and don't intend to run or test it, then you do not need a target computer (also called a test computer). If, however, you would like to deploy, run and test this sample driver, then you need a second computer that will server as your target computer. Instructions are provided in the **Run the sample** section to show you how to set up the target computer - also referred to as *provisioning* a target computer.
+If you simply want to Build this sample driver and don't intend to run or test it, then you do not need a target computer (also called a test computer). If, however, you would like to deploy, run and test this sample driver, then you need a second computer that will serve as your target computer. Instructions are provided in the **Run the sample** section to show you how to set up the target computer - also referred to as *provisioning* a target computer.
Perform the following steps to build this sample driver.
-**1. Open the driver solution in Visual Studio**
+### 1. Open the driver solution in Visual Studio
In Microsoft Visual Studio, Click **File** \> **Open** \> **Project/Solution...** and navigate to the folder that contains the sample files (for example, *C:\Windows-driver-samples\audio\sysvad*). Double-click the *sysvad* solution file.
-In Visual Studio locate the Solution Explorer. (If this is not already open, choose **Solution Explorer** from the **View** menu.) In Solution Explorer, you can see one solution that has eight projects.
+In Visual Studio locate the Solution Explorer. (If this is not already open, choose **Solution Explorer** from the **View** menu.) In Solution Explorer, you can see one solution that has seven projects.
-**2. Set the sample's configuration and platform**
+### 2. Set the sample's configuration and platform
-In Solution Explorer, right-click **Solution 'sysvad' (8 projects)**, and choose **Configuration Manager**. Make sure that the configuration and platform settings are the same for the eight projects. By default, the configuration is set to **Debug**, and the platform is set to **Win32** for all the projects. If you make any configuration and/or platform changes for one project, you must make the same changes for the remaining three projects.
+In Solution Explorer, right-click **Solution 'sysvad' (7 of 7 projects)**, and choose **Configuration Manager**. Make sure that the configuration and platform settings are the same for the seven projects. By default, the configuration is set to **Debug**, and the platform is set to **Win32** for all the projects. If you make any configuration and/or platform changes for one project, you must make the same changes for all the remaining projects.
-**3. Build the sample using Visual Studio**
+### 3. Build the sample using Visual Studio
In Visual Studio, click **Build** \> **Build Solution**.
-**4. Locate the built driver package**
+### 4. Locate the built driver package
In File Explorer, navigate to the folder that contains the sample files. For example, you would navigate to *C:\\Windows-driver-samples\\audio\\sysvad*, if that's the folder you specified in the preceding Step 1.
@@ -73,101 +68,118 @@ In the folder, the location of the driver package varies depending on the config
The package should contain these files:
-File | Description
------|------------
-TabletAudioSample.sys OR PhoneAudioSample.sys| The driver file.
-SwapAPO.dll | The swap APO.
-DelayAPO.dll | The delay APO.
-KWSApo.dll | The KWS APO.
-sysvad.cat | A signed catalog file, which serves as the signature for the entire package.
-TabletAudioSample.inf | An information (INF) file that contains information needed to install the driver.
-PhoneAudioSample.inf | An information (INF) file that contains information needed to install the driver.
-KeywordDetectorContosoAdapter.dll | Sample Keyword detector adapter.
+| File | Description |
+| --- | --- |
+| TabletAudioSample.sys | The driver file. |
+| DelayAPO.dll | The delay APO. |
+| KeywordDetectorContosoAdapter.dll | Sample Keyword detector adapter. |
+| KWSApo.dll | The KWS APO. |
+| SwapAPO.dll | The swap APO. |
+| sysvad.cat | A signed catalog file, which serves as the signature for the entire package. |
+| ComponentizedApoSample.inf | A componentized information (INF) file that installs an APO device. |
+| ComponentizedAudioSample.inf | A componentized information (INF) file that contains information needed to install the Tablet Audio Sample driver. |
+| ComponentizedAudioSampleExtension.inf | An extension information (INF) file that extends the Tablet Audio Sample driver functionality by associating an APO device to it. |
+| TabletAudioSample.inf | A non-componentized information (INF) file that contains information needed to install the driver. |
+
+For more information on extension INF files, see [Using an extension INF file](https://docs.microsoft.com/windows-hardware/drivers/install/using-an-extension-inf-file).
-Run the sample
---------------
+## Run the sample
The computer where you install the driver is called the *target computer* or the *test computer*. Typically this is a separate computer from the computer on which you develop and build the driver package. The computer where you develop and build the driver is called the *host computer*.
-The process of moving the driver package to the target computer and installing the driver is called *deploying* the driver. You can deploy the sample driver, TabletAudioSample or PhoneAudioSample, automatically or manually.
+The process of moving the driver package to the target computer and installing the driver is called *deploying* the driver. You can deploy the TabletAudioSample sample driver automatically or manually.
-### Automatic deployment
+### Prepare the target computer
-Before you automatically deploy a driver, you must provision the target computer. Verify that the target computer has an ethernet cable connecting it to your local network, and that your host and target computers can ping each other. Then perform the following steps to prepare your host and target computers.
+First of all, install the latest [Windows Driver Kit](https://docs.microsoft.com/windows-hardware/drivers/download-the-wdk) (WDK) on the target computer.
-**1. Provision the target computer**
+Before you manually deploy a driver, you must prepare the target computer by turning on test signing and by installing a certificate. You also need to locate the DevCon tool in your WDK installation. After that you're ready to run the built driver sample.
-On the target computer install the latest [Windows Driver Kit](http://msdn.microsoft.com/en-us/windows/hardware/gg454513.aspx) (WDK), and then when the installation is completed, navigate to the following folder:
+Open a Command Prompt window as Administrator. Then enter the following command:
-\\Program Files (x86)\\Windows Kits\\10\\Remote\\<*architecture*>\\
+`bcdedit /set TESTSIGNING ON`
-For example, if your target computer is an x64 machine, you would navigate to:
+and reboot the target computer.
-\\Program Files (x86)\\Windows Kits\\10\\Remote\\x64\\
+> [!IMPORTANT]
+> Before using BCDEdit to change boot information you may need to temporarily suspend Windows security features such as BitLocker and Secure Boot on the test PC.
-Double-click the *WDK Test Target Setup x64-x64\_en-us.msi* file to run it. This program prepares the target computer for provisioning.
+Re-enable these security features when testing is complete and appropriately manage the test PC, when the security features are disabled.
-On the host computer, in Visual Studio click **Driver** \> **Test** \> **Configure Computers...**, and then click **Add a new computer**.
+After rebooting, navigate to the Tools folder in your WDK installation and locate the DevCon tool. For example, look in the following folder:
-Type the name of the target computer, select **Provision computer and choose debugger settings**, and click **Next**. In the next window, verify that the **Connection Type** is set to Network. Leave the other (default) settings as they are, and click **Next**. For more information about the settings in this window, see [Getting Set Up for Debugging](http://msdn.microsoft.com/en-us/library/windows/hardware/hh450944(v=vs.85).aspx).
+C:\\Program Files (x86)\\Windows Kits\\10\\Tools\\x64\\devcon.exe
-**2. Prepare the host computer**
+Copy *devcon.exe* to a folder on the target computer where it is easier to find. For example, create a *C:\\Tools* folder and copy *devcon.exe* to that folder.
-If you haven't already done so, then preform the steps in the **Build the sample** section, to build the sample driver.
+Create a folder on the target for the built driver package (for example, *C:\\SysvadDriver*). Copy all the files from the built driver package on the host computer and save them to the folder that you created on the target computer.
-In Visual Studio, in Solution Explorer, right click **package** (lower case), and choose **Properties**. Navigate to **Configuration Properties** \> **Driver Install** \> **Deployment**.
+Create a folder on the target computer for the certificate created by the build process. For example, you could create a folder named *C:\\Certificates* on the target computer, and then copy *package.cer* to it from the host computer. You can find this certificate in the same folder on the host computer, as the *package* folder that contains the built driver files. On the target computer, right-click the certificate file, and click **Install**, then follow the prompts to install the test certificate.
-Check , **Enable deployment** and check **Remove previous driver versions before deployment**. For **Target Computer Name**, select the name of a target computer that you provisioned previously. Select **Hardware ID Driver Update**, and enter *ROOT\Sysvad_TabletAudioSample* for the hardware ID. Click **OK**.
+If you need more detailed instructions for setting up the target computer, see [Preparing a Computer for Manual Driver Deployment](https://docs.microsoft.com/windows-hardware/drivers/develop/preparing-a-computer-for-manual-driver-deployment).
-On the **Build** menu, choose **Deploy Package** or **Build Solution**. This will deploy the sample driver to your target computer.
+#### A note on signatures
-On the target computer, perform the steps in the **Test the sample** section to test the sample driver.
+Since most of these binary files are executed in kernel mode, it is important that they are signed and, optionally, to have a kernel debugger attached.
-### Manual deployment
+Without any signature or kernel debugger, the driver will not be installed in the target computer. With a kernel debugger attached, the driver can be installed and the driver files (.sys extension) would be loaded, but any user mode files (.dll files) will not be loaded.
-Before you manually deploy a driver, you must prepare the target computer by turning on test signing and by installing a certificate. You also need to locate the DevCon tool in your WDK installation. After that you're ready to run the built driver sample.
+The only way of installing and executing the whole driver sample is to have all the files (.sys, .dll and .cat) signed with a trusted certificate. This will allow the entire driver to be loaded even without a kernel debugger attached.
-**1. Prepare the target computer**
+For more information on the subject, see [Driver signing](https://docs.microsoft.com/windows-hardware/drivers/install/driver-signing).
-Open a Command Prompt window as Administrator. Then enter the following command:
+### Install the driver
-**bcdedit /set TESTSIGNING ON**
+#### Componentized INF files
-Reboot the target computer. Then navigate to the Tools folder in your WDK installation and locate the DevCon tool. For example, look in the following folder:
+The TabletAudioSample driver package contains a sample driver, an extension sample and an APO software component. The following instructions show you how to install and test the sample driver, the APO component and then the extension to apply the software component to the driver.
-*C:\\Program Files (x86)\\Windows Kits\\10\\Tools\\x64\\devcon.exe*
+First, the base INF, *ComponentizedAudioSample.inf*, has to be installed. To install it, open a Command Prompt window as administrator on the target computer, then navigate to your driver package folder and enter the following command:
-Copy *devcon.exe* to a folder on the target computer where it is easier to find. For example, create a *C:\\Tools* folder and copy *devcon.exe* to that folder.
+`devcon install ComponentizedAudioSample.inf Root\Sysvad_ComponentizedAudioSample`
-Create a folder on the target for the built driver package (for example, *C:\\SysvadDriver*). Copy all the files from the built driver package on the host computer and save them to the folder that you created on the target computer.
+If you get an error message about *devcon* not being recognized, try adding the path to the *devcon* tool. For example, if you copied it to a folder called *C:\\Tools*, then try using the following command:
-Create a folder on the target computer for the certificate created by the build process. For example, you could create a folder named *C:\\Certificates* on the target computer, and then copy *package.cer* to it from the host computer. You can find this certificate in the same folder on the host computer, as the *package* folder that contains the built driver files. On the target computer, right-click the certificate file, and click **Install**, then follow the prompts to install the test certificate.
+`C:\\tools\\devcon install ComponentizedAudioSample.inf Root\Sysvad_ComponentizedAudioSample`
-If you need more detailed instructions for setting up the target computer, see [Preparing a Computer for Manual Driver Deployment](https://docs.microsoft.com/en-us/windows-hardware/drivers/develop/preparing-a-computer-for-manual-driver-deployment).
+This installs the base Tablet Audio Sample driver with a hardware ID of "Root\Sysvad_ComponentizedAudioSample".
-**2. Install the driver**
+Then, either the extension INF (*ComponentizedAudioSampleExtension.inf*) or the APO INF (*ComponentizedApoSample.inf*) can be installed.
-The TabletAudioSample or PhoneAudioSample driver package contains a sample driver and 2 driver extension samples. The following instructions show you how to install and test the sample driver.
+If the extension INF is installed first, it will create a new component called *Audio Proxy APO Sample*. Until the APO is installed, this component will appear in Device Manager under the section of Software Components, because it does not have a driver attached yet. The driver is attached by installing the APO INF.
-The INF file required for installing this driver is *TabletAudioSample.inf*.
+If the APO is installed first, it will install a driver, but it will not create a device, so the APO will not be visible in Device Manager until the extension INF creates a software component that will then have the APO driver installed.
-On the target computer, open a Command Prompt window as Administrator. Navigate to your driver package folder, and enter the following command:
+Both extension and APO INFs can be installed by right-clicking on any of the files and selecting "install" from the menu.
-**devcon dp_add TabletAudioSample.inf**
+Once the three componentized INF files are installed, an APO device should appear in Device Manager and the *Microsoft Virtual Audio Device (WDM) - Tablet Audio Sample* device should now be named *SYSVAD (with APO Extensions)*.
-If you get an error message about *devcon* not being recognized, try adding the path to the *devcon* tool. For example, if you copied it to a folder called *C:\\Tools*, then try using the following command:
+For more detailed instructions, see [Provision a computer for driver deployment and testing](https://docs.microsoft.com/windows-hardware/drivers/gettingstarted/provision-a-target-computer-wdk-8-1).
+
+#### Single INF files
-**C:\\tools\\devcon dp_add TabletAudioSample.inf**
+TabletAudioSample also contains an INF file, tabletaudiosample.inf, which install the sample driver using a single INF file.
-For more detailed instructions, see [Configuring a Computer for Driver Deployment, Testing, and Debugging](http://msdn.microsoft.com/en-us/library/windows/hardware/hh698272(v=vs.85).aspx).
+Componentized driver packages are required since Windows 10 1809 release. However, for backward compatibility, instructions on how to install the TabletAudioSample.inf are provided below.
+
+On the target computer, open a Command Prompt window as Administrator. Navigate to your driver package folder, and enter the following command:
+
+`devcon dp_add TabletAudioSample.inf`
After successfully installing the sample driver, you're now ready to test it.
### Test the driver
-On the target computer, in a Command Prompt window, enter **devmgmt** to open Device Manager. In Device Manager, on the **View** menu, choose **Devices by type**. In the device tree, locate *Microsoft Virtual Audio Device (WDM) - Tablet Audio Sample*. This is typically under the **Sound, video and game controllers** node.
+On the target computer, in a Command Prompt window, enter **devmgmt.msc** to open Device Manager. In Device Manager, on the **View** menu, choose **Devices by type**. In the device tree, locate *SYSVAD (with APO Extensions)*. This is typically under the **Sound, video and game controllers** node.
+
+On the target computer, open Control Panel and navigate to **Hardware and Sound** \> **Manage audio devices**. In the Sound dialog box, select the speaker icon labeled as *SYSVAD (with APO Extensions)*, then click **Set Default**, but do not click **OK**. This will keep the Sound dialog box open.
+
+Locate an MP3 or other audio file on the target computer and double-click to play it. Then in the Sound dialog box, verify that there is activity in the volume level indicator associated with the *SYSVAD (with APO Extensions)* driver.
+
+## HLK testing
-On the target computer, open Control Panel and navigate to **Hardware and Sound** \> **Manage audio devices**. In the Sound dialog box, select the speaker icon labeled as *Microsoft Virtual Audio Device (WDM) - Tablet Audio Sample*, then click **Set Default**, but do not click **OK**. This will keep the Sound dialog box open.
+The sample uploaded here is tested using the latest HLK version available to make sure it passes all audio tests in the current playlist. However, since it is a virtual audio driver it does not implement audio mixing and simulates capture and loopback by generating a tone. Given these limitations, there are some HLK tests that are expected to fail because they rely on the described functionality.
-Locate an MP3 or other audio file on the target computer and double-click to play it. Then in the Sound dialog box, verify that there is activity in the volume level indicator associated with the *Microsoft Virtual Audio Device (WDM) - Tablet Audio Sample* driver.
+In the case of audio tests, one of these exceptions is the Hardware Offload of Audio Processing Test. This test is aimed at devices that support offload capabilities and performs checks to make sure that the device complies with the appropiate requirements. In the particular case of SysVAD, this test will fail for endpoints with offload and loopback.
+For endpoints with offload, the test will fail because the driver includes offload pins but it does not implement a mixer with volume, mute and peak meter nodes, etc. For the case of endpoints with loopback, the test will fail because the driver simulates loopback by returning a sine tone instead of performing real mixing of streams in host and/or offload pins. \ No newline at end of file
diff --git a/audio/sysvad/TabletAudioSample/ComponentizedApoSample.inx b/audio/sysvad/TabletAudioSample/ComponentizedApoSample.inx
index 4ee84101..be9428fb 100644
--- a/audio/sysvad/TabletAudioSample/ComponentizedApoSample.inx
+++ b/audio/sysvad/TabletAudioSample/ComponentizedApoSample.inx
Binary files differ
diff --git a/audio/sysvad/TabletAudioSample/ComponentizedAudioSample.inx b/audio/sysvad/TabletAudioSample/ComponentizedAudioSample.inx
index a5e6e73f..8f04a934 100644
--- a/audio/sysvad/TabletAudioSample/ComponentizedAudioSample.inx
+++ b/audio/sysvad/TabletAudioSample/ComponentizedAudioSample.inx
Binary files differ
diff --git a/audio/sysvad/TabletAudioSample/ComponentizedAudioSampleExtension.inx b/audio/sysvad/TabletAudioSample/ComponentizedAudioSampleExtension.inx
index 4f29c985..1c89827a 100644
--- a/audio/sysvad/TabletAudioSample/ComponentizedAudioSampleExtension.inx
+++ b/audio/sysvad/TabletAudioSample/ComponentizedAudioSampleExtension.inx
Binary files differ
diff --git a/audio/sysvad/TabletAudioSample/TabletAudioSample.vcxproj b/audio/sysvad/TabletAudioSample/TabletAudioSample.vcxproj
index f7752502..6d60c71a 100644
--- a/audio/sysvad/TabletAudioSample/TabletAudioSample.vcxproj
+++ b/audio/sysvad/TabletAudioSample/TabletAudioSample.vcxproj
@@ -263,7 +263,7 @@
<AdditionalDependencies>%(AdditionalDependencies);.\..\EndpointsCommon\$(IntDir)\EndpointsCommon.lib</AdditionalDependencies>
</Link>
<ClCompile>
- <!--
+ <!--
Use one of the following pre-processor defines to select the right power management:
- _USE_IPortClsRuntimePower
- _USE_SingleComponentMultiFxStates
@@ -284,6 +284,9 @@
<PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
</ResourceCompile>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<Link>
@@ -303,6 +306,9 @@
<PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
</ResourceCompile>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Link>
@@ -322,6 +328,9 @@
<PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
</ResourceCompile>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<Link>
@@ -341,6 +350,9 @@
<PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
</ResourceCompile>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Link>
@@ -360,6 +372,9 @@
<PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
</ResourceCompile>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Link>
@@ -379,6 +394,9 @@
<PreprocessorDefinitions>%(PreprocessorDefinitions);_USE_WAVERT_;SYSVAD_BTH_BYPASS;SYSVAD_USB_SIDEBAND;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\EndpointsCommon</AdditionalIncludeDirectories>
</ResourceCompile>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\adapter.cpp" />
diff --git a/audio/sysvad/TabletAudioSample/tabletaudiosample.inx b/audio/sysvad/TabletAudioSample/tabletaudiosample.inx
index ba96faee..58ee4d88 100644
--- a/audio/sysvad/TabletAudioSample/tabletaudiosample.inx
+++ b/audio/sysvad/TabletAudioSample/tabletaudiosample.inx
Binary files differ
diff --git a/audio/sysvad/adapter.cpp b/audio/sysvad/adapter.cpp
index 7cfa54ee..cc7960a5 100644
--- a/audio/sysvad/adapter.cpp
+++ b/audio/sysvad/adapter.cpp
@@ -1177,6 +1177,7 @@ Return Value:
switch (stack->MinorFunction)
{
+#ifdef SYSVAD_USB_SIDEBAND
case IRP_MN_QUERY_DEVICE_RELATIONS:
switch (stack->Parameters.QueryDeviceRelations.Type)
@@ -1203,6 +1204,7 @@ Return Value:
break;
}
break;
+#endif // SYSVAD_USB_SIDEBAND
case IRP_MN_REMOVE_DEVICE:
case IRP_MN_SURPRISE_REMOVAL:
diff --git a/audio/sysvad/common.cpp b/audio/sysvad/common.cpp
index f88ca093..9292c96d 100644
--- a/audio/sysvad/common.cpp
+++ b/audio/sysvad/common.cpp
@@ -302,7 +302,9 @@ class CAdapterCommon :
STDMETHODIMP_(VOID) Cleanup();
+#ifdef SYSVAD_USB_SIDEBAND
STDMETHODIMP_(NTSTATUS) UpdatePowerRelations(_In_ PIRP Irp);
+#endif // SYSVAD_USB_SIDEBAND
//=====================================================================
// friends
@@ -608,7 +610,9 @@ Return Value:
InterlockedDecrement(&CAdapterCommon::m_AdapterInstances);
ASSERT(CAdapterCommon::m_AdapterInstances == 0);
+#ifdef SYSVAD_USB_SIDEBAND
ASSERT(IsListEmpty(&m_PowerRelations));
+#endif // SYSVAD_USB_SIDEBAND
} // ~CAdapterCommon
//=============================================================================
@@ -2300,6 +2304,7 @@ CAdapterCommon::Cleanup()
EmptySubdeviceCache();
}
+#ifdef SYSVAD_USB_SIDEBAND
//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
@@ -2426,6 +2431,7 @@ Exit:
return status;
}
+#endif // SYSVAD_USB_SIDEBAND
//=============================================================================
#pragma code_seg("PAGE")
diff --git a/audio/sysvad/common.h b/audio/sysvad/common.h
index 794b3797..8ce0a866 100644
--- a/audio/sysvad/common.h
+++ b/audio/sysvad/common.h
@@ -206,6 +206,7 @@ typedef struct _PIN_DEVICE_FORMATS_AND_MODES
} PIN_DEVICE_FORMATS_AND_MODES, *PPIN_DEVICE_FORMATS_AND_MODES;
+
//
// Parameter module handler function prototypes.
//
@@ -670,7 +671,9 @@ DECLARE_INTERFACE_(IAdapterCommon, IUnknown)
STDMETHOD_(VOID, Cleanup)();
+#ifdef SYSVAD_USB_SIDEBAND
STDMETHOD_(NTSTATUS, UpdatePowerRelations)(_In_ PIRP Irp);
+#endif // SYSVAD_USB_SIDEBAND
STDMETHOD_(NTSTATUS, NotifyEndpointPair)
(
diff --git a/audio/sysvad/sysvad.sln b/audio/sysvad/sysvad.sln
index 2965165c..6a58b6df 100644
--- a/audio/sysvad/sysvad.sln
+++ b/audio/sysvad/sysvad.sln
@@ -1,4 +1,4 @@
-
+
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27703.2042
@@ -9,8 +9,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "KeywordDetectorAdapter", "K
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EndpointsCommon", "EndpointsCommon", "{0B4B8E51-20A8-43A4-A8DA-42FF90D628AC}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PhoneAudioSample", "PhoneAudioSample", "{D0DBEBE9-0DCC-4EA7-966B-C029C1334D9E}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TabletAudioSample", "TabletAudioSample", "{C06F6070-75EE-4F57-8D35-4AC2AB08D029}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "package\package.VcxProj", "{830B14D5-0E32-4F9E-AEFA-4C9F6FC13C2A}"
@@ -19,11 +17,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeywordDetectorContosoAdapt
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EndpointsCommon", "EndpointsCommon\EndpointsCommon.vcxproj", "{33E61864-6F2C-4F9F-BE70-8F8985A4F283}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PhoneAudioSample", "PhoneAudioSample\PhoneAudioSample.vcxproj", "{FABA4668-DB5E-4F6C-9D25-A0B25AD084EE}"
- ProjectSection(ProjectDependencies) = postProject
- {33E61864-6F2C-4F9F-BE70-8F8985A4F283} = {33E61864-6F2C-4F9F-BE70-8F8985A4F283}
- EndProjectSection
-EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TabletAudioSample", "TabletAudioSample\TabletAudioSample.vcxproj", "{E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}"
ProjectSection(ProjectDependencies) = postProject
{33E61864-6F2C-4F9F-BE70-8F8985A4F283} = {33E61864-6F2C-4F9F-BE70-8F8985A4F283}
@@ -83,18 +76,6 @@ Global
{33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Release|Win32.Build.0 = Release|Win32
{33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Release|x64.ActiveCfg = Release|x64
{33E61864-6F2C-4F9F-BE70-8F8985A4F283}.Release|x64.Build.0 = Release|x64
- {FABA4668-DB5E-4F6C-9D25-A0B25AD084EE}.Debug|ARM64.ActiveCfg = Debug|ARM64
- {FABA4668-DB5E-4F6C-9D25-A0B25AD084EE}.Debug|ARM64.Build.0 = Debug|ARM64
- {FABA4668-DB5E-4F6C-9D25-A0B25AD084EE}.Debug|Win32.ActiveCfg = Debug|Win32
- {FABA4668-DB5E-4F6C-9D25-A0B25AD084EE}.Debug|Win32.Build.0 = Debug|Win32
- {FABA4668-DB5E-4F6C-9D25-A0B25AD084EE}.Debug|x64.ActiveCfg = Debug|x64
- {FABA4668-DB5E-4F6C-9D25-A0B25AD084EE}.Debug|x64.Build.0 = Debug|x64
- {FABA4668-DB5E-4F6C-9D25-A0B25AD084EE}.Release|ARM64.ActiveCfg = Release|ARM64
- {FABA4668-DB5E-4F6C-9D25-A0B25AD084EE}.Release|ARM64.Build.0 = Release|ARM64
- {FABA4668-DB5E-4F6C-9D25-A0B25AD084EE}.Release|Win32.ActiveCfg = Release|Win32
- {FABA4668-DB5E-4F6C-9D25-A0B25AD084EE}.Release|Win32.Build.0 = Release|Win32
- {FABA4668-DB5E-4F6C-9D25-A0B25AD084EE}.Release|x64.ActiveCfg = Release|x64
- {FABA4668-DB5E-4F6C-9D25-A0B25AD084EE}.Release|x64.Build.0 = Release|x64
{E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Debug|ARM64.ActiveCfg = Debug|ARM64
{E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Debug|ARM64.Build.0 = Debug|ARM64
{E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF}.Debug|Win32.ActiveCfg = Debug|Win32
@@ -151,7 +132,6 @@ Global
{830B14D5-0E32-4F9E-AEFA-4C9F6FC13C2A} = {FA56D96B-290B-4C73-A5E1-02C1861D3224}
{E0F02048-78A4-4FE8-B863-66E6CB6A2C37} = {DBD14E7B-7F95-4743-86E3-4E16FA43F990}
{33E61864-6F2C-4F9F-BE70-8F8985A4F283} = {0B4B8E51-20A8-43A4-A8DA-42FF90D628AC}
- {FABA4668-DB5E-4F6C-9D25-A0B25AD084EE} = {D0DBEBE9-0DCC-4EA7-966B-C029C1334D9E}
{E4DF0EEE-D35B-47F2-A9B1-41EA97C465FF} = {C06F6070-75EE-4F57-8D35-4AC2AB08D029}
{8851AB85-70B3-4798-A149-BA366DF9EC25} = {D86F9A10-C48D-4048-A03C-DD7BCA6E165F}
{691F1D0F-CA50-46CD-8BBA-A59E9E8EB601} = {D86F9A10-C48D-4048-A03C-DD7BCA6E165F}
diff --git a/audio/tests/HLK/ThirdPartyApoTests/APODeviceTest.cpp b/audio/tests/HLK/ThirdPartyApoTests/APODeviceTest.cpp
new file mode 100644
index 00000000..ca3b3a7a
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/APODeviceTest.cpp
@@ -0,0 +1,1120 @@
+#include <stdafx.h>
+
+#include <initguid.h>
+#include "propkey.h"
+#include <AudioClient.h>
+#include <functiondiscoverykeys.h>
+#include <DevPKey.h>
+#include <AudioEngineBaseAPOP.h>
+#include "TestMediaType.h"
+#include "audioconnectionutil.h"
+#include <audioenginebaseapo.h>
+
+#include <WexTestClass.h>
+
+#include <list>
+#include <memory>
+
+#include "APODeviceTest.h"
+#include "Wrappers.h"
+#include "FormatHelpers.h"
+
+
+using namespace std;
+using namespace wil;
+using namespace WEX::Logging;
+using namespace WEX::Common;
+
+#define REGKEY_AUDIOSERVICE L"Software\\Microsoft\\Windows\\CurrentVersion\\Audio"
+#define REGVALUE_SKIPRTHEAP L"SkipRTHeap"
+
+// Forward Declarations
+bool SetupSkipRTHeap();
+bool CleanupSkipRTHeap();
+HRESULT VerifyCustomFormatSupport(CAPODevice * deviceUnderTest);
+HRESULT VerifyValidFrameCount(CAPODevice * deviceUnderTest);
+HRESULT VerifyAPODataStreaming(CAPODevice * deviceUnderTest);
+HRESULT VerifyActivateDeactivate(CAPODevice * deviceUnderTest);
+HRESULT FillConnection
+(
+ UNCOMPRESSEDAUDIOFORMAT* Format,
+ UINT_PTR pBuffer,
+ UINT32 u32ExtraFrameCount,
+ UINT32 u32MaxFrameCount,
+ APO_CONNECTION_DESCRIPTOR* pConnection
+);
+
+bool CApoDeviceTests::setUpMethod()
+{
+ // Populate a vector of each endpoint on the system and wrap it with
+ // an APO test wrapper which will save necessary APO information for
+ // test cases
+ WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
+ com_ptr_nothrow<IMMDeviceEnumerator> spEnumerator;
+ com_ptr_nothrow<IMMDeviceCollection> spDevices;
+
+ UINT32 cDevices;
+ PROPVARIANT var;
+
+ PropVariantInit(&var);
+
+ VERIFY_SUCCEEDED(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, IID_PPV_ARGS(&spEnumerator)));
+ VERIFY_SUCCEEDED(spEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &spDevices));
+ VERIFY_SUCCEEDED(spDevices->GetCount(&cDevices));
+
+ // Initialize an APO device list for each device on the system
+ for(UINT32 i = 0; i < cDevices; i++)
+ {
+ com_ptr_nothrow<IMMDevice> spEndpoint;
+ com_ptr_nothrow<IPropertyStore> spPropertyStore;
+
+ VERIFY_SUCCEEDED(spDevices->Item(i, &spEndpoint));
+ VERIFY_SUCCEEDED(spEndpoint->OpenPropertyStore(STGM_READ, &spPropertyStore));
+ VERIFY_SUCCEEDED(spPropertyStore->GetValue(PKEY_Device_FriendlyName, &var));
+ VERIFY_ARE_EQUAL(VT_LPWSTR, var.vt);
+ LOG_OUTPUT(L"Setting Up Endpoint: %s", var.pwszVal);
+
+ unique_ptr<CAPODeviceList> pTestModule(new CAPODeviceList());
+ pTestModule->Initialize(wistd::move(spEndpoint), var.pwszVal);
+ m_testDeviceWrapperList.push_back(move(pTestModule));
+
+ PropVariantClear(&var);
+ }
+
+ return SetupSkipRTHeap();
+}
+
+bool CApoDeviceTests::tearDownMethod()
+{
+ m_testDeviceWrapperList.clear();
+ return CleanupSkipRTHeap();
+}
+
+void CApoDeviceTests::TestAPOInitialize()
+{
+ // In the event that one initialization fails fully, we do not want to fail
+ // the whole test. Instead, mark the test as failed and complete it on all
+ // devices.
+ bool testSucceeded = true;
+
+ m_testDeviceWrapperList.remove_if([&](auto & deviceWrapper) {
+
+ // Print Device Friendly name
+ LOG_OUTPUT(L"Endpoint Under Test: %ls", deviceWrapper->m_deviceName);
+
+ HRESULT hr = deviceWrapper->AddSysFxDevices();
+
+ if (hr == S_FALSE)
+ {
+ // No cause for failure here. Just remove the device from our test list
+ // as it appears to be inactive or has no third party APOs
+ return true;
+ }
+
+ if (FAILED(hr))
+ {
+ LOG_ERROR(L"Device initialization failed with error: %x", hr);
+ testSucceeded = false;
+ }
+ return false;
+
+ });
+
+ VERIFY_IS_TRUE(testSucceeded);
+}
+
+void CApoDeviceTests::TestCustomFormatSupport()
+{
+ bool testSucceeded = true;
+
+ TestAPOInitialize();
+
+ for(auto const& deviceWrapper : m_testDeviceWrapperList)
+ {
+ // Print Device Friendly name
+ LOG_OUTPUT(L"Endpoint Under Test: %ls", deviceWrapper->m_deviceName);
+
+ // Test over each SysFX device on the device
+ for (auto const& apo : deviceWrapper->m_DeviceList)
+ {
+ if (apo->IsProxyApo())
+ {
+ GUID proxyGuid;
+ unique_cotaskmem_string proxyString;
+
+ apo->GetClsID(&proxyGuid);
+ StringFromCLSID(proxyGuid, &proxyString);
+
+ LOG_OUTPUT(L"Proxy APO found. Skipping: %ls", proxyString.get());
+ continue;
+ }
+
+ HRESULT hr = VerifyCustomFormatSupport(apo.get());
+
+ if (hr == S_FALSE)
+ {
+ LOG_OUTPUT(L"\tAPO does not support custom formats. This is not an error");
+ }
+
+ if (FAILED(hr))
+ {
+ LOG_ERROR(L"\tTest Custom Format Support failed with error: (0x%08lx)", hr);
+ testSucceeded = false;
+ }
+ }
+ }
+
+ VERIFY_IS_TRUE(testSucceeded);
+}
+
+void CApoDeviceTests::TestValidFrameCount()
+{
+ bool testSucceeded = true;
+
+ TestAPOInitialize();
+
+ for(auto const& deviceWrapper : m_testDeviceWrapperList)
+ {
+ // Print Device Friendly name
+ LOG_OUTPUT(L"Endpoint Under Test: %ls", deviceWrapper->m_deviceName);
+
+ // Test over each SysFX device on the device
+ for (auto const& apo : deviceWrapper->m_DeviceList)
+ {
+ if (apo->IsProxyApo())
+ {
+ GUID proxyGuid;
+ unique_cotaskmem_string proxyString;
+
+ apo->GetClsID(&proxyGuid);
+ StringFromCLSID(proxyGuid, &proxyString);
+
+ LOG_OUTPUT(L"\tProxy APO found. Skipping: %ls", proxyString.get());
+ continue;
+ }
+
+ HRESULT hr = VerifyValidFrameCount(apo.get());
+
+ if (FAILED(hr))
+ {
+ LOG_ERROR(L"\tTest Valid Frame Count failed with error: (0x%08lx)", hr);
+ testSucceeded = false;
+ }
+ }
+ }
+
+ VERIFY_IS_TRUE(testSucceeded);
+}
+
+void CApoDeviceTests::TestAPODataStreaming()
+{
+ bool testSucceeded = true;
+
+ TestAPOInitialize();
+
+ for(auto const& deviceWrapper : m_testDeviceWrapperList)
+ {
+ // Print Device Friendly name
+ LOG_OUTPUT(L"Endpoint Under Test: %ls", deviceWrapper->m_deviceName);
+
+ // Test over each SysFX device on the device
+ for (auto const& apo : deviceWrapper->m_DeviceList)
+ {
+ if (apo->IsProxyApo())
+ {
+ GUID proxyGuid;
+ unique_cotaskmem_string proxyString;
+
+ apo->GetClsID(&proxyGuid);
+ StringFromCLSID(proxyGuid, &proxyString);
+
+ LOG_OUTPUT(L"\tProxy APO found. Skipping: %ls", proxyString.get());
+ continue;
+ }
+
+ HRESULT hr = VerifyAPODataStreaming(apo.get());
+
+ if (FAILED(hr))
+ {
+ LOG_ERROR(L"\tTest APO Data Streaming failed with error: (0x%08lx)", hr);
+ testSucceeded = false;
+ }
+ }
+ }
+
+ VERIFY_IS_TRUE(testSucceeded);
+}
+
+void CApoDeviceTests::TestActivateDeactivate()
+{
+ bool testSucceeded = true;
+
+ TestAPOInitialize();
+
+ for(auto const& deviceWrapper : m_testDeviceWrapperList)
+ {
+ // Print Device Friendly name
+ LOG_OUTPUT(L"Endpoint Under Test: %ls", deviceWrapper->m_deviceName);
+
+ // Test over each SysFX device on the device
+ for (auto const& apo : deviceWrapper->m_DeviceList)
+ {
+ if (apo->IsProxyApo())
+ {
+ GUID proxyGuid;
+ unique_cotaskmem_string proxyString;
+
+ apo->GetClsID(&proxyGuid);
+ StringFromCLSID(proxyGuid, &proxyString);
+
+ LOG_OUTPUT(L"\tProxy APO found. Skipping: %ls", proxyString.get());
+ continue;
+ }
+
+ HRESULT hr = VerifyActivateDeactivate(apo.get());
+
+ if (FAILED(hr))
+ {
+ LOG_ERROR(L"\tTest Activate and Deactivate failed with error: (0x%08lx)", hr);
+ testSucceeded = false;
+ }
+ }
+ }
+
+ VERIFY_IS_TRUE(testSucceeded);
+}
+
+HRESULT VerifyValidFrameCount(CAPODevice* deviceUnderTest)
+{
+ wil::com_ptr<IAudioProcessingObject> pIAPO;
+ wil::com_ptr<IAudioProcessingObjectRT> pIAPORT;
+ wil::com_ptr<IAudioProcessingObjectConfiguration> pIAPOConfig;
+
+ if (deviceUnderTest == nullptr)
+ {
+ LOG_ERROR(L"\tCould not instantiate SysFx object.\n");
+ return E_NOINTERFACE;
+ }
+
+ LOG_RETURN_IF_FAILED(deviceUnderTest->GetAPOInterfaces(&pIAPO, &pIAPORT, &pIAPOConfig), L"\tCould not instantiate IAudioProcessingObject interface.");
+
+ APO_CONNECTION_PROPERTY inputProperty, outputProperty;
+ APO_CONNECTION_DESCRIPTOR inputDescriptor, outputDescriptor;
+ APO_CONNECTION_PROPERTY *pInputConnProp = &inputProperty, *pOutputConnProp = &outputProperty;
+ APO_CONNECTION_DESCRIPTOR *pInputConnDesc = &inputDescriptor, *pOutputConnDesc = &outputDescriptor;
+ UNCOMPRESSEDAUDIOFORMAT defaultFormat {};
+
+ FillFormat(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 2, sizeof(float), sizeof(float) * 8, static_cast<float>(cFrameRate), KSAUDIO_SPEAKER_STEREO, &defaultFormat);
+
+ LOG_RETURN_IF_FAILED(SetupConnection(pInputConnDesc, pOutputConnDesc, pInputConnProp, pOutputConnProp, &defaultFormat),
+ L"\tSetupConnection failed");
+
+ LOG_RETURN_IF_FAILED(LockForProcess(pIAPOConfig.get(), 1, &pInputConnDesc, 1, &pOutputConnDesc),
+ L"\tLockForProcess failed");
+
+ // setup vectors
+ FLOAT32 *pf32Input, *pf32Output;
+ pf32Input = (FLOAT32*)pInputConnProp->pBuffer;
+ pf32Output = (FLOAT32*)pOutputConnProp->pBuffer;
+ for (UINT32 index = 0; index < cFrameCountToProcess; index++)
+ {
+ pf32Input[index] = 0.5f;
+ pf32Output[index] = 0.0f;
+ }
+
+ APOProcess(pIAPORT.get(), 1, &pInputConnProp, 1, &pOutputConnProp);
+
+ LOG_RETURN_HR_IF(pOutputConnProp->u32ValidFrameCount != cFrameCountToProcess,
+ E_FAIL,
+ L"\tFAIL: APOProcess output(%d) and input(%d) buffer valid frame counts does not match.\n", pOutputConnProp->u32ValidFrameCount, cFrameCountToProcess);
+
+ LOG_RETURN_IF_FAILED(UnlockForProcess(pIAPOConfig.get()),
+ L"\tUnlock for process failed");
+
+ LOG_RETURN_IF_FAILED(DestroyConnection(pInputConnDesc), L"\tFailed to DestroyConnection");
+ LOG_RETURN_IF_FAILED(DestroyConnection(pOutputConnDesc), L"\tFailed to DestroyConnection");
+
+ return S_OK;
+}
+
+HRESULT VerifyCustomFormatSupport(CAPODevice * deviceUnderTest)
+{
+ com_ptr_nothrow<IAudioProcessingObject> pIAPO = nullptr;
+ com_ptr_nothrow<IAudioSystemEffectsCustomFormats> pICustomFormats = nullptr;
+ com_ptr_nothrow<IEndpointUtility> pIEPUtility = nullptr;
+ IMMDevice * pIMMDevice = nullptr;
+ UINT iFormat;
+
+ if (deviceUnderTest == nullptr)
+ {
+ LOG_ERROR(L"\tCould not instantiate SysFx object.");
+ return E_NOINTERFACE;
+ }
+
+ if (nullptr == (pIMMDevice = deviceUnderTest->GetEndpoint()))
+ {
+ LOG_ERROR(L"\tUnable to get endpoint for device.");
+ return E_NOINTERFACE;
+ }
+
+ LOG_RETURN_IF_FAILED(pIMMDevice->Activate(__uuidof(IEndpointUtility), CLSCTX_INPROC_SERVER, NULL, (void**)&pIEPUtility),
+ L"\tUnable to activate utility interface");
+
+ LOG_RETURN_IF_FAILED(deviceUnderTest->GetAPOInterfaces(&pIAPO, nullptr, nullptr), L"\tCould not instantiate IAudioProcessingObject interface.");
+
+ if (pIAPO == nullptr)
+ {
+ LOG_ERROR(L"\tFAIL: Could not instantiate IAudioProcessingObject interface.");
+ return E_NOINTERFACE;
+ }
+
+ HRESULT hrQi = QIInternal(pIAPO.get(), __uuidof(IAudioSystemEffectsCustomFormats), (void**)&pICustomFormats);
+
+ if (E_NOINTERFACE == hrQi)
+ {
+ // This GFX does not support custom formats...
+ LOG_OUTPUT(L"\tSysFx does not support custom formats (QueryInterface for "
+ "IAudioSystemEffectsCustomFormats returns E_NOINTERFACE).");
+ return S_FALSE;
+ }
+
+ LOG_RETURN_IF_FAILED(hrQi, L"\tQueryInterface for IAudioSystemEffectsCustomFormats returned error.");
+
+
+ // Custom formats are available and supported
+ LOG_OUTPUT(L"\tIAudioSystemEffectsCustomFormats available on SysFx.");
+
+ LOG_RETURN_IF_FAILED(pICustomFormats->GetFormatCount(&iFormat),
+ L"\tIAudioSystemEffectsCustomFormats::GetFormatCount failed");
+
+ // No matter what we want to test all formats. However if one fails, make sure we fail
+ // the test as well
+ bool allFormatsSucceeded = true;
+
+ for (; iFormat; --iFormat)
+ {
+ com_ptr_nothrow<IAudioMediaType> pIFormat = nullptr;
+ com_ptr_nothrow<IAudioMediaType> pIFormatSuggested = nullptr;
+ LPWSTR strFormatName = NULL;
+ com_ptr_nothrow<IPartsList> pIParts = nullptr;
+ KSDATAFORMAT_WAVEFORMATEX * pKsFormat = NULL;
+ HRESULT hrFormatSupport = S_OK;
+
+ if (FAILED(hrFormatSupport = pICustomFormats->GetFormat(iFormat - 1, &pIFormat)))
+ {
+ LOG_ERROR(L"\tFAIL: IAudioSystemEffectsCustomFormats::GetFormat returned "
+ "error (0x%08lx).",
+ hrFormatSupport);
+ allFormatsSucceeded = false;
+
+ continue;
+ }
+
+ if (FAILED(hrFormatSupport = pICustomFormats->GetFormatRepresentation(iFormat - 1, &strFormatName)))
+ {
+ LOG_ERROR(L"\tFAIL: IAudioSystemEffectsCustomFormats::"
+ "GetFormatRepresentation returned error (0x%08lx)",
+ hrFormatSupport);
+ allFormatsSucceeded = false;
+
+ continue;
+ }
+
+ LOG_OUTPUT(L"\tVerifying format support for: [%ls]...", strFormatName);
+
+ // Custom format, must be supported on the output side of SysFx...
+ hrFormatSupport = IsOutputFormatSupported(pIAPO.get(), NULL, pIFormat.get(), &pIFormatSuggested);
+ const WAVEFORMATEX* original = pIFormat->GetAudioFormat();
+ const WAVEFORMATEX* suggested = pIFormatSuggested->GetAudioFormat();
+
+ LOG_OUTPUT(L"\tWaveFormatEx pIFormat - tag: %u, channels: %u, samplespersec: %u, avgbytespersec: %u, blockalign: %u, bitspersample: %u, cbsize: %u",
+ original->wFormatTag, original->nChannels, original->nSamplesPerSec, original->nAvgBytesPerSec, original->nBlockAlign,
+ original->wBitsPerSample, original->cbSize);
+
+ LOG_OUTPUT(L"\tWaveFormatEx pIFormatSuggested - tag: %u, channels: %u, samplespersec: %u, avgbytespersec: %u, blockalign: %u, bitspersample: %u, cbsize: %u",
+ suggested->wFormatTag, suggested->nChannels, suggested->nSamplesPerSec, suggested->nAvgBytesPerSec, suggested->nBlockAlign,
+ suggested->wBitsPerSample, suggested->cbSize);
+
+ if (S_FALSE == hrFormatSupport)
+ {
+ LOG_ERROR(L"\tFAIL: IsOutputFormatSupported returns S_FALSE with a suggested format");
+ allFormatsSucceeded = false;
+ }
+ else if (S_OK != hrFormatSupport)
+ {
+ LOG_ERROR(L"\tFAIL: IsOutputFormatSupported returns error (0x%08lx)",
+ hrFormatSupport);
+ allFormatsSucceeded = false;
+ }
+ else
+ {
+ if (pIFormatSuggested == nullptr)
+ {
+ LOG_ERROR(L"\tFAIL: IsOutputFormatSupported returns S_OK, but does not "
+ "suggest format.");
+ allFormatsSucceeded = false;
+ }
+ else
+ {
+ if (!IsEqualFormat(pIFormat.get(), pIFormatSuggested.get()))
+ {
+ LOG_ERROR(L"\tFAIL: IsOutputFormatSupported returns S_OK, but "
+ "returns a different format.");
+ allFormatsSucceeded = false;
+ }
+ else
+ {
+ LOG_OUTPUT(L"\tIsOutputFormatSupported supports custom format.");
+ }
+ }
+ }
+
+ pKsFormat = CreateKSDataFromWFX((WAVEFORMATEX*)pIFormat->GetAudioFormat());
+
+ if (pKsFormat == NULL)
+ {
+ LOG_ERROR(L"\tFAIL: Unable to create KSDATAFORMAT from PWAVEFORMATEX.");
+ allFormatsSucceeded = false;
+
+ continue;
+ }
+
+ {
+ unique_cotaskmem_ptr<KSDATAFORMAT_WAVEFORMATEX> formatBuffer(pKsFormat);
+
+ // Custom format, must be supported by endpoint...
+ hrFormatSupport = pIEPUtility->FindHostConnector(
+ (KSDATAFORMAT*)formatBuffer.get(),
+ formatBuffer->DataFormat.FormatSize,
+ FALSE,
+ &pIParts);
+
+ if (S_OK != hrFormatSupport)
+ {
+ LOG_ERROR(L"\tFAIL: Endpoint does not support custom format with error: (0x%08lx)", hrFormatSupport);
+ allFormatsSucceeded = false;
+ }
+ else
+ {
+ LOG_OUTPUT(L"\tEndpoint supports custom format.");
+ }
+ }
+ }
+
+ return allFormatsSucceeded;
+}
+
+HRESULT VerifyAPODataStreaming(CAPODevice* deviceUnderTest)
+{
+ wil::com_ptr<IAudioProcessingObject> pIAPO;
+ wil::com_ptr<IAudioProcessingObjectRT> pIAPORT;
+ wil::com_ptr<IAudioProcessingObjectConfiguration> pIAPOConfig;
+ APO_REG_PROPERTIES *pRegProperties = NULL;
+
+ if (deviceUnderTest == nullptr)
+ {
+ LOG_ERROR(L"\tCould not instantiate SysFx object.\n");
+ return E_NOINTERFACE;
+ }
+
+ LOG_RETURN_IF_FAILED(deviceUnderTest->GetAPOInterfaces(&pIAPO, &pIAPORT, &pIAPOConfig), L"\tCould not instantiate IAudioProcessingObject interface.");
+
+ APO_CONNECTION_PROPERTY inputProperty, outputProperty;
+ APO_CONNECTION_DESCRIPTOR inputDescriptor, outputDescriptor;
+ APO_CONNECTION_PROPERTY *pInputConnProp = &inputProperty, *pOutputConnProp = &outputProperty;
+ APO_CONNECTION_DESCRIPTOR *pInputConnDesc = &inputDescriptor, *pOutputConnDesc = &outputDescriptor;
+ UNCOMPRESSEDAUDIOFORMAT defaultFormat {};
+
+ FillFormat(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 2, sizeof(float), sizeof(float) * 8, static_cast<float>(cFrameRate), KSAUDIO_SPEAKER_STEREO, &defaultFormat);
+
+ LOG_RETURN_IF_FAILED(SetupConnection(pInputConnDesc, pOutputConnDesc, pInputConnProp, pOutputConnProp, &defaultFormat),
+ L"\tSetupConnection failed");
+
+ LOG_RETURN_IF_FAILED(LockForProcess(pIAPOConfig.get(), 1, &pInputConnDesc, 1, &pOutputConnDesc),
+ L"\tLockForProcess failed");
+
+ // setup vectors
+ FLOAT32 *pf32Input, *pf32Output;
+ pf32Input = (FLOAT32*)pInputConnProp->pBuffer;
+ pf32Output = (FLOAT32*)pOutputConnProp->pBuffer;
+ for (UINT32 index = 0; index < cFrameCountToProcess; index++)
+ {
+ pf32Input[index] = 0.5f;
+ pf32Output[index] = INFINITY;
+ }
+
+ APOProcess(pIAPORT.get(), 1, &pInputConnProp, 1, &pOutputConnProp);
+
+ GetRegistrationProperties(pIAPO.get(), &pRegProperties);
+
+ // Tests to make sure that in place APO have the correct data.
+ for (UINT32 index = 0; index < cFrameCountToProcess; index++)
+ {
+ // This will also check NaN along with INF
+ LOG_RETURN_HR_IF(!isfinite(pf32Output[index]), E_FAIL,
+ L"\tFAIL: APOProcess output(%f) is not a number or infinite.\n", pf32Output[index]);
+ }
+
+ LOG_RETURN_IF_FAILED(UnlockForProcess(pIAPOConfig.get()),
+ L"\tUnlock for process failed");
+
+ if (APO_FLAG_INPLACE == (pRegProperties->Flags & APO_FLAG_INPLACE))
+ {
+ LOG_RETURN_IF_FAILED(LockForProcess(pIAPOConfig.get(), 1, &pInputConnDesc, 1, &pInputConnDesc),
+ L"\tLockForProcess failed");
+
+ // setup vector
+ pf32Input = (FLOAT32 *)pInputConnProp->pBuffer;
+ for (UINT32 index = 0; index < cFrameCountToProcess; index++)
+ {
+ pf32Input[index] = 0.5f;
+ }
+
+ APOProcess(pIAPORT.get(), 1, &pInputConnProp, 1, &pInputConnProp);
+
+ LOG_RETURN_IF_FAILED(UnlockForProcess(pIAPOConfig.get()),
+ L"\tUnlock for process failed");
+ }
+
+ LOG_RETURN_IF_FAILED(DestroyConnection(pInputConnDesc), L"\tFailed to DestroyConnection");
+ LOG_RETURN_IF_FAILED(DestroyConnection(pOutputConnDesc), L"\tFailed to DestroyConnection");
+
+ return S_OK;
+}
+
+HRESULT VerifyActivateDeactivate(CAPODevice* deviceUnderTest)
+{
+ GUID clsid;
+ WCHAR ComRegistrationPath[1024];
+ WCHAR file[1024];
+ PWSTR end;
+ size_t cchRemaining;
+ DWORD dwSize = sizeof(WCHAR) * 1024;
+
+ if (deviceUnderTest == nullptr)
+ {
+ LOG_ERROR(L"\tCould not instantiate SysFx object.\n");
+ return E_NOINTERFACE;
+ }
+
+ deviceUnderTest->GetClsID(&clsid);
+
+ LOG_RETURN_IF_FAILED(StringCchPrintfEx(ComRegistrationPath, ARRAYSIZE(ComRegistrationPath), &end, &cchRemaining, 0, L"CLSID\\{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\\InprocServer32",
+ clsid.Data1, clsid.Data2, clsid.Data3, clsid.Data4[0], clsid.Data4[1], clsid.Data4[2], clsid.Data4[3], clsid.Data4[4], clsid.Data4[5], clsid.Data4[6], clsid.Data4[7]),
+ L"\tFailed to create string to find file name for DLL.");
+
+ LONG error = RegGetValue(HKEY_CLASSES_ROOT, ComRegistrationPath, nullptr, RRF_RT_REG_SZ, nullptr, file, &dwSize);
+
+ if (error != ERROR_SUCCESS)
+ {
+ LOG_RETURN_IF_FAILED(HRESULT_FROM_WIN32(error), L"\tFAILED to get the registry value.");
+ }
+
+ auto loadAPO = LoadLibrary(file);
+
+ if (loadAPO == NULL)
+ {
+ DWORD err = GetLastError();
+ HRESULT hr = HRESULT_FROM_WIN32(err);
+ if (SUCCEEDED(hr))
+ {
+ hr = E_FAIL;
+ }
+ LOG_RETURN_IF_FAILED(hr, L"\tFAILED to load the APO.");
+ }
+
+ BOOL bFreed = FreeLibrary(loadAPO);
+
+ if (!bFreed)
+ {
+ DWORD err = GetLastError();
+ HRESULT hr = HRESULT_FROM_WIN32(err);
+ if (SUCCEEDED(hr))
+ {
+ hr = E_FAIL;
+ }
+ LOG_RETURN_IF_FAILED(hr, L"\tFAILED to free the loaded APO.");
+ }
+
+ return S_OK;
+}
+
+struct APO_PROPERTIES {
+ PROPERTYKEY key;
+ LPARAM apoType;
+ LPCWSTR apoTypeName;
+ DWORD dwMajorVersion;
+ DWORD dwMinorVersion;
+ } PKEY_FX_EFFECTS[] = {
+ {PKEY_FX_PostMixEffectClsid, DT_GFX, L"GFX " ,6, 0},
+ {PKEY_FX_PreMixEffectClsid, DT_LFX, L"LFX ", 6, 0},
+ {PKEY_FX_StreamEffectClsid, DT_SFX, L"SFX ", 6, 3},
+ {PKEY_FX_ModeEffectClsid, DT_MFX, L"MFX ", 6, 3},
+ {PKEY_FX_EndpointEffectClsid, DT_EFX, L"EFX ", 6, 3},
+ // Composite effects
+ {PKEY_CompositeFX_StreamEffectClsid, DT_SFX, L"Composite SFX", 10, 0},
+ {PKEY_CompositeFX_ModeEffectClsid, DT_MFX, L"Composite MFX", 10, 0},
+ {PKEY_CompositeFX_EndpointEffectClsid, DT_EFX, L"Composite EFX", 10, 0},
+ // Offload effects
+ {PKEY_FX_Offload_StreamEffectClsid, DT_SFX, L"Offload SFX", 10, 0},
+ {PKEY_FX_Offload_ModeEffectClsid, DT_MFX, L"Offload MFX", 10, 0},
+ {PKEY_CompositeFX_Offload_StreamEffectClsid, DT_SFX, L"Composite Offload SFX", 10, 0},
+ {PKEY_CompositeFX_Offload_ModeEffectClsid, DT_MFX, L"Composite Offload MFX", 10, 0},
+ // Keyword Detector effects
+ {PKEY_FX_KeywordDetector_StreamEffectClsid, DT_SFX, L"KeywordDetector SFX", 10, 0},
+ {PKEY_FX_KeywordDetector_ModeEffectClsid, DT_MFX, L"KeywordDetector MFX", 10, 0},
+ {PKEY_FX_KeywordDetector_EndpointEffectClsid, DT_EFX, L"KeywordDetector EFX", 10, 0},
+ {PKEY_CompositeFX_KeywordDetector_StreamEffectClsid, DT_SFX, L"Composite KeywordDetector SFX", 10, 0},
+ {PKEY_CompositeFX_KeywordDetector_ModeEffectClsid, DT_MFX, L"Composite KeywordDetector MFX", 10, 0},
+ {PKEY_CompositeFX_KeywordDetector_EndpointEffectClsid, DT_EFX, L"Composite KeywordDetector EFX", 10, 0},
+ };
+
+CAPODevice::CAPODevice
+(
+ IMMDevice *pIEndpoint,
+ LPCWSTR pszClassId,
+ LPCWSTR pszEndpoint,
+ IPropertyStore *pIStoreDevice,
+ IPropertyStore *pIStoreFx,
+ LPARAM apoType,
+ LPCWSTR apoTypeName,
+ LPCWSTR pszAttachedDevice,
+ BOOL bProxyAPO
+)
+: m_pRegProps(NULL), m_fValid(FALSE)
+{
+ {
+ // Getting PnpId from property store...
+ PROPVARIANT pv;
+ com_ptr_nothrow<IMMDeviceEnumerator> pIDeviceEnumerator;
+ com_ptr_nothrow<IMMDevice> pIMMDevNode;
+ com_ptr_nothrow<IPropertyStore> pIDNPropStore;
+
+ LOG_RETURN_VOID_IF_FAILED(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, IID_PPV_ARGS(&pIDeviceEnumerator)),
+ L"\tCoCreateInstance for MMDeviceEnumerator returned error");
+
+ PropVariantInit(&pv);
+ auto clearPropVariantOnScopeExit = scope_exit([&]
+ {
+ PropVariantClear(&pv);
+ });
+
+ LOG_RETURN_VOID_IF_FAILED(pIStoreDevice->GetValue(PKEY_Endpoint_Devnode, &pv), L"\tFailed to get endpoint device");
+
+ if (VT_LPWSTR != pv.vt)
+ {
+ LOG_ERROR(L"\tEnpoint Devnode property key is of the incorrect type");
+ return;
+ }
+
+ LOG_RETURN_VOID_IF_FAILED(pIDeviceEnumerator->GetDevice(pv.pwszVal, &pIMMDevNode), L"\tGetting device (%s) from the enumerator failed", pv.pwszVal);
+
+ PropVariantClear(&pv);
+
+ LOG_RETURN_VOID_IF_FAILED(pIMMDevNode->OpenPropertyStore(STGM_READ, &pIDNPropStore), L"\tFailed to open device property store");
+
+ PropVariantInit(&pv);
+
+ LOG_RETURN_VOID_IF_FAILED(pIDNPropStore->GetValue((PROPERTYKEY&)DEVPKEY_Device_InstanceId, &pv), L"\tFailed to get device instance id from device prop store");
+
+ if (VT_LPWSTR != pv.vt)
+ {
+ LOG_ERROR(L"\tDevice instance ID is of the incorrect type");
+ return;
+ }
+
+ m_szPnPId = wil::make_cotaskmem_string_nothrow(pv.pwszVal, sizeof(m_szPnPId));
+ }
+
+ LOG_RETURN_VOID_IF_FAILED(CLSIDFromString((LPOLESTR)pszClassId, &m_gClsID), L"\tCLSIDFromString failed");
+
+ m_szAttachedDevice = wil::make_cotaskmem_string_nothrow(pszAttachedDevice, wcslen(pszAttachedDevice));
+ m_szEndpoint = wil::make_cotaskmem_string_nothrow(pszEndpoint, wcslen(pszEndpoint));
+
+ PROPVARIANT value;
+ PropVariantInit(&value);
+ if (SUCCEEDED(pIStoreFx->GetValue(PKEY_ItemNameDisplay, &value)))
+ {
+ if (value.vt == VT_LPWSTR)
+ {
+ m_sApoName = wil::make_cotaskmem_string_nothrow(value.pwszVal, wcslen(value.pwszVal));
+ }
+ PropVariantClear(&value);
+ }
+
+
+ LOG_RETURN_VOID_IF_FAILED(CoCreateInstance(m_gClsID, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&m_pIUnknown)), L"\tCoCreateInstance for IUnknown returned error");
+
+
+ LOG_RETURN_VOID_IF_FAILED(m_pIUnknown->QueryInterface(__uuidof(IAudioProcessingObject), (void**)&m_pIAPO),
+ L"\tCoCreateInstance for IAudioProcessingObject returned error");
+
+
+ // Getting DeviceCollection
+ {
+ PROPVARIANT pvFormat;
+
+ // the standard KSDATAFORMAT_WAVEFORMATEX only contains a
+ // WAVEFORMATEX, but we need the extensible format so
+ // we define this type here:
+ typedef struct {
+ KSDATAFORMAT DataFormat;
+ WAVEFORMATEXTENSIBLE WFXtensible;
+ } KS_WFExtensible;
+
+ KS_WFExtensible ksWfx;
+
+ // initialize the structure
+ PropVariantInit(&pvFormat);
+
+ // Clear the prop variant on scope exit
+ auto clearFormatOnExit = scope_exit([&] {
+ PropVariantClear(&pvFormat);
+ });
+
+ LOG_RETURN_VOID_IF_FAILED(pIStoreDevice->GetValue(PKEY_AudioEngine_DeviceFormat, &pvFormat), L"\tGet PKEY_AudioEngine_Device format returned error");
+
+ if (pvFormat.vt == VT_BLOB)
+ {
+ if (pvFormat.blob.cbSize != sizeof(WAVEFORMATEXTENSIBLE))
+ {
+ LOG_ERROR(L"\tpvFormat.blob.cbSize (%zu) != sizeof(WAVEFORMATEXTENSIBLE) (%zu)\n", pvFormat.blob.cbSize, sizeof(WAVEFORMATEXTENSIBLE));
+ return;
+ }
+ }
+ else
+ {
+ LOG_ERROR(L"\tFormat is not VT_BLOB, Q != %c\n", VARTYPE(pvFormat.vt));
+ return;
+ }
+
+
+ LPWAVEFORMATEX pbWfxDevice = NULL;
+ ULONG cbWfxDevice = 0;
+
+ pbWfxDevice = (WAVEFORMATEX*)pvFormat.blob.pBlobData;
+ cbWfxDevice = pvFormat.blob.cbSize;
+
+ ksWfx.DataFormat.FormatSize = sizeof(KSDATAFORMAT) + cbWfxDevice;
+ ksWfx.DataFormat.Flags = 0;
+ ksWfx.DataFormat.SampleSize = 0;
+ ksWfx.DataFormat.Reserved = 0;
+ ksWfx.DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
+ ksWfx.DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ ksWfx.DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
+ CopyMemory( &(ksWfx.WFXtensible), pbWfxDevice, cbWfxDevice );
+
+ com_ptr_nothrow<IEndpointUtility2> pIEPUtil;
+ LOG_RETURN_VOID_IF_FAILED(pIEndpoint->Activate(__uuidof(IEndpointUtility2), CLSCTX_ALL, NULL, (void**)&pIEPUtil), L"\tpIMMDevice->Activate returned error");
+
+ LOG_RETURN_VOID_IF_FAILED(pIEPUtil->GetHostConnectorDeviceCollection2((PKSDATAFORMAT)&ksWfx, sizeof(ksWfx), TRUE,
+ eHostProcessConnector, &m_pIDevCollection, &m_nSoftwareIoDeviceInCollection, &m_nSoftwareIoConnectorIndex),
+ L"\tGetting device collection returned error");
+ }
+
+ // Saved off for InitializeAPO()
+ m_pIEndpoint = pIEndpoint;
+ m_pIEPStore = pIStoreDevice;
+ m_pIFXStore = pIStoreFx;
+ m_lpType = apoType;
+ m_sApoTypeName = wil::make_cotaskmem_string_nothrow(apoTypeName, wcslen(apoTypeName));;
+ m_bProxyAPO = bProxyAPO;
+
+ // Initialize SysFx!!
+ LOG_RETURN_VOID_IF_FAILED(InitializeAPO(m_pIAPO.get()), L"\tpIAPO->Initialize returned error");
+
+ m_fValid = TRUE;
+}
+
+CAPODevice::~CAPODevice(void)
+{
+ if (NULL != m_pRegProps)
+ {
+ CoTaskMemFree(m_pRegProps);
+ m_pRegProps = NULL;
+ }
+}
+
+
+HRESULT CAPODevice::InitializeAPO
+(
+ IAudioProcessingObject *pIAPO
+)
+{
+ LOG_RETURN_HR_IF(pIAPO == nullptr, E_POINTER, L"IAudioProcessingObject is null");
+
+ if(DT_SMEFX & GetDeviceType())
+ {
+ APOInitSystemEffects2 sysfxInitParams2 = {0};
+ // Setup initialization struct
+ sysfxInitParams2.APOInit.cbSize = sizeof(APOInitSystemEffects2);
+ sysfxInitParams2.APOInit.clsid = m_gClsID;
+ sysfxInitParams2.pReserved = NULL;
+ sysfxInitParams2.pDeviceCollection = m_pIDevCollection.get();
+ sysfxInitParams2.pAPOEndpointProperties = m_pIEPStore.get();
+ sysfxInitParams2.pAPOSystemEffectsProperties = m_pIFXStore.get();
+ sysfxInitParams2.InitializeForDiscoveryOnly = TRUE;
+ sysfxInitParams2.AudioProcessingMode = AUDIO_SIGNALPROCESSINGMODE_DEFAULT;
+ sysfxInitParams2.nSoftwareIoDeviceInCollection = m_nSoftwareIoDeviceInCollection;
+ sysfxInitParams2.nSoftwareIoConnectorIndex = m_nSoftwareIoConnectorIndex;
+
+ return pIAPO->Initialize(sysfxInitParams2.APOInit.cbSize, (BYTE*)(&sysfxInitParams2));
+ }
+ else if (DT_LGFX & GetDeviceType())
+ {
+ APOInitSystemEffects sysfxInitParams = {0};
+ // Setup initialization struct
+ sysfxInitParams.APOInit.cbSize = sizeof(sysfxInitParams);
+ sysfxInitParams.APOInit.clsid = m_gClsID;
+ sysfxInitParams.pAPOEndpointProperties = m_pIEPStore.get();
+ sysfxInitParams.pAPOSystemEffectsProperties = m_pIFXStore.get();
+ sysfxInitParams.pDeviceCollection = m_pIDevCollection.get();
+ sysfxInitParams.pReserved = NULL;
+
+ return (pIAPO->Initialize(sizeof(sysfxInitParams), (BYTE*)&sysfxInitParams));
+ }
+
+ // We should never get here unless we are initializing a first party APO (which we shouldn't be)
+ LOG_ERROR(L"SFX is of unknown type. Type is: %d", GetDeviceType());
+ return E_FAIL;
+}
+
+HRESULT CAPODevice::GetAPOInterfaces
+(
+ IAudioProcessingObject **ppIAPO,
+ IAudioProcessingObjectRT **ppIAPORT,
+ IAudioProcessingObjectConfiguration **ppIAPOConfig
+)
+{
+ if (ppIAPO != nullptr)
+ {
+ LOG_RETURN_IF_FAILED(UnknownQIInternal(m_pIUnknown.get(), __uuidof(IAudioProcessingObject), (void**)ppIAPO),
+ L"\tCoCreateInstance for IAudioProcessingObject failed");
+ }
+
+ if (ppIAPORT != nullptr)
+ {
+ LOG_RETURN_IF_FAILED(UnknownQIInternal(m_pIUnknown.get(), __uuidof(IAudioProcessingObjectRT), (void**)ppIAPORT),
+ L"\tCoCreateInstance for IAudioProcessingObjectRT failed");
+ }
+
+ if (ppIAPOConfig != nullptr)
+ {
+ LOG_RETURN_IF_FAILED(UnknownQIInternal(m_pIUnknown.get(), __uuidof(IAudioProcessingObjectConfiguration), (void**)ppIAPOConfig),
+ L"\tCoCreateInstance for IAudioProcessingObjectConfiguration failed");
+ }
+
+ return S_OK;
+}
+
+//--------------------------------------------------------------------------
+// CAPODeviceList constructor
+CAPODeviceList::CAPODeviceList ()
+{
+}
+
+//--------------------------------------------------------------------------
+// ~CAPODeviceList destructor
+
+CAPODeviceList::~CAPODeviceList(VOID)
+{
+ m_DeviceList.clear();
+
+ RegDeleteKeyValue(HKEY_LOCAL_MACHINE,
+ REGKEY_AUDIO_SOFTWARE,
+ PREVENT_APOTEST_CRASH_OR_REPORT_ON_APO_EXCEPTION);
+}
+
+HRESULT CAPODeviceList::AddSysFxDevices()
+{
+ HRESULT hr = S_OK;
+ bool allApoDevicesValid = true;
+ com_ptr_nothrow<IMMEndpoint> pIMMEndpoint;
+ com_ptr_nothrow<IMMEndpointInternal> pIMMEndpointInt;
+ com_ptr_nothrow<IPropertyStore> pIPropertyStoreDevice;
+ com_ptr_nothrow<IPropertyStore> pIPropertyStoreFX;
+ com_ptr_nothrow<IDeviceTopology> pIDeviceTopology;
+ com_ptr_nothrow<IConnector> pIConnector;
+ LPCWSTR strConnectedDevice = NULL;
+ PROPVARIANT pvName;
+ PROPVARIANT pv;
+ PROPVARIANT pvProxy;
+ BOOL bAPOProxy;
+
+
+ if (FAILED(hr = m_spDevice->Activate(__uuidof(IDeviceTopology), CLSCTX_INPROC_SERVER, NULL, (void**)&pIDeviceTopology)))
+ {
+ if (E_NOINTERFACE == hr)
+ {
+ LOG_OUTPUT(L"\tDevice is not active. Removing from test cases");
+ // There's the possibility that this legit if device is not active.
+ return S_FALSE;
+ }
+
+ return hr;
+ }
+
+ LOG_RETURN_IF_FAILED(pIDeviceTopology->GetConnector(0, &pIConnector),
+ L"\tFailed to get device connector");
+
+ LOG_RETURN_IF_FAILED(pIConnector->GetDeviceIdConnectedTo((LPWSTR *)&strConnectedDevice),
+ L"\tFailed to get connected device ID");
+
+ LOG_RETURN_IF_FAILED(m_spDevice->QueryInterface(__uuidof(IMMEndpoint), (void**)&pIMMEndpoint),
+ L"\tQueryInterfacce for IMMEndpoint failed");
+
+ LOG_RETURN_IF_FAILED(pIMMEndpoint->QueryInterface(__uuidof(IMMEndpointInternal), (void**)&pIMMEndpointInt),
+ L"\tQueryInterface for IMMEndpointInternal failed");
+
+ LOG_RETURN_IF_FAILED(m_spDevice->OpenPropertyStore(STGM_READ, &pIPropertyStoreDevice),
+ L"\tFailed to open property store for device");
+
+ LOG_RETURN_IF_FAILED(pIMMEndpointInt->TryOpenFXPropertyStore(STGM_READ, &pIPropertyStoreFX),
+ L"\tFailed to Open SysFX property store for device");
+
+ if (!pIPropertyStoreFX)
+ {
+ // This device doesn't appear to have any SysFX
+ LOG_OUTPUT(L"\tThis device probably doesn't have any SysFx. Skipping and removing from test");
+ return S_FALSE;
+ }
+
+ PropVariantInit(&pvName);
+ if (SUCCEEDED(pIPropertyStoreDevice->GetValue(PKEY_Device_FriendlyName, &pvName)))
+ {
+ if (VT_LPWSTR != V_VT(&pvName))
+ {
+ LOG_OUTPUT(L"\tFriendlyName value is not a string.");
+ }
+ }
+ else
+ {
+ LOG_OUTPUT(L"\tIPropertyStore::GetValue returned error.");
+ }
+
+
+ OSVERSIONINFO ver = {0};
+ ver.dwOSVersionInfoSize = sizeof(ver);
+
+ GetVersionEx(&ver);
+
+ for(int i = 0; i < ARRAYSIZE(PKEY_FX_EFFECTS); i++)
+ {
+ if (ver.dwMajorVersion < PKEY_FX_EFFECTS[i].dwMajorVersion ||
+ (ver.dwMajorVersion == PKEY_FX_EFFECTS[i].dwMajorVersion &&
+ ver.dwMinorVersion < PKEY_FX_EFFECTS[i].dwMinorVersion))
+ {
+ continue;
+ }
+
+ PropVariantInit(&pv);
+ hr = pIPropertyStoreFX->GetValue(PKEY_FX_EFFECTS[i].key, &pv);
+ LOG_OUTPUT(L"\tPKEY_FX_EFFECTS[%i] - GetValue PKEY_FX_EFFECTS[%i].key - 0x%x", i, i, hr);
+ if (S_OK == hr)
+ {
+ LOG_OUTPUT(L"\tPKEY_FX_EFFECTS[%i] - V_VT(&pv) - %i", i, V_VT(&pv));
+ if (VT_LPWSTR == V_VT(&pv))
+ {
+ bAPOProxy = FALSE;
+ PropVariantInit(&pvProxy);
+
+ // Check if mode effect is proxy
+ if (PKEY_FX_EFFECTS[i].apoType & DT_MFX)
+ {
+ hr = pIPropertyStoreFX->GetValue(PKEY_MFX_ProcessingModes_Supported_For_Streaming, &pvProxy);
+ LOG_OUTPUT(L"\tPKEY_FX_EFFECTS[%i] - GetValue MFX - 0x%x", i, hr);
+ if (S_OK == hr)
+ {
+ bAPOProxy = (pvProxy.vt != (VT_VECTOR | VT_LPWSTR)) ? TRUE : FALSE;
+ }
+ }
+
+ // Check if endpoint effect is proxy
+ if (PKEY_FX_EFFECTS[i].apoType & DT_EFX)
+ {
+ hr = pIPropertyStoreFX->GetValue(PKEY_EFX_ProcessingModes_Supported_For_Streaming, &pvProxy);
+ LOG_OUTPUT(L"\tPKEY_FX_EFFECTS[%i] - GetValue EFX - 0x%x", i, hr);
+ if (S_OK == hr)
+ {
+ bAPOProxy = (pvProxy.vt != (VT_VECTOR | VT_LPWSTR)) ? TRUE : FALSE;
+ }
+ }
+
+ LOG_OUTPUT(L"\tLooking at Audio Processing Object %ls\n", pv.pwszVal);
+
+ unique_ptr<CAPODevice> pSysFxDevice(new CAPODevice(m_spDevice.get(), pv.pwszVal, pvName.pwszVal, pIPropertyStoreDevice.get(),
+ pIPropertyStoreFX.get(), PKEY_FX_EFFECTS[i].apoType, PKEY_FX_EFFECTS[i].apoTypeName,
+ strConnectedDevice, bAPOProxy));
+
+ if (NULL != pSysFxDevice)
+ {
+ if (pSysFxDevice->IsValid())
+ {
+ pSysFxDevice->m_fSelected = TRUE;
+ m_DeviceList.push_back(move(pSysFxDevice));
+ }
+ else
+ {
+ LOG_ERROR(L"\tInvalid sysFX device encountered");
+ }
+ }
+
+ PropVariantClear(&pvProxy);
+ }
+ else if ((VT_LPWSTR | VT_VECTOR) == V_VT(&pv) && pv.calpwstr.cElems > 0)
+ {
+ UINT32 cClsids = pv.calpwstr.cElems;
+ bAPOProxy = FALSE;
+
+ for (UINT32 j = 0; j < cClsids; j++)
+ {
+ LOG_OUTPUT(L"\tLooking at Audio Processing Object %ls\n", pv.calpwstr.pElems[j]);
+
+ unique_ptr<CAPODevice> pSysFxDevice(new CAPODevice(m_spDevice.get(), pv.calpwstr.pElems[j], pvName.pwszVal, pIPropertyStoreDevice.get(),
+ pIPropertyStoreFX.get(), PKEY_FX_EFFECTS[i].apoType, PKEY_FX_EFFECTS[i].apoTypeName,
+ strConnectedDevice, bAPOProxy));
+
+ if (NULL != pSysFxDevice)
+ {
+ if (pSysFxDevice->IsValid())
+ {
+ pSysFxDevice->m_fSelected = TRUE;
+ m_DeviceList.push_back(move(pSysFxDevice));
+ }
+ else
+ {
+ LOG_ERROR(L"\tInvalid sysFX device encountered");
+ }
+ }
+ }
+ }
+ }
+ PropVariantClear(&pv);
+ }
+
+ return allApoDevicesValid ? S_OK : E_FAIL;
+}
+
+HRESULT CAPODeviceList::Initialize(wil::com_ptr_nothrow<IMMDevice> pDevice, LPWSTR deviceName)
+{
+ if (pDevice == nullptr || deviceName == nullptr)
+ {
+ LOG_ERROR(L"\tIMMDevice is null");
+ return E_INVALIDARG;
+ }
+
+ m_spDevice = pDevice;
+
+ wcscat(m_deviceName, deviceName);
+
+ DWORD dwValue = 1;
+ // Set registry entry so AudioDG won't crash during IAudioProcessingObjectRT function calls
+ RETURN_IF_WIN32_ERROR(RegSetKeyValue(HKEY_LOCAL_MACHINE,
+ REGKEY_AUDIO_SOFTWARE,
+ PREVENT_APOTEST_CRASH_OR_REPORT_ON_APO_EXCEPTION,
+ REG_DWORD,
+ &dwValue,
+ sizeof(dwValue)));
+
+ return S_OK;
+}
diff --git a/audio/tests/HLK/ThirdPartyApoTests/APODeviceTest.h b/audio/tests/HLK/ThirdPartyApoTests/APODeviceTest.h
new file mode 100644
index 00000000..31225995
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/APODeviceTest.h
@@ -0,0 +1,180 @@
+#include <stdafx.h>
+
+class CApoDeviceTests;
+
+class CAPODevice
+{
+ public:
+ CAPODevice
+ (
+ IMMDevice *pIEndpoint,
+ LPCWSTR pszClassId,
+ LPCWSTR pszEndpoint,
+ IPropertyStore *pIStoreDevice,
+ IPropertyStore *pIStoreFx,
+ LPARAM apoType,
+ LPCWSTR apoName,
+ LPCWSTR pszAttachedDevice,
+ BOOL bProxyAPO
+ );
+ CAPODevice
+ (
+ IAudioProcessingObject *pIAPO,
+ LPCWSTR pszClassId
+ );
+ ~CAPODevice(void);
+ HRESULT InitializeAPO(IAudioProcessingObject *pIAPO);
+ DWORD GetDeviceType() { return (DWORD)(m_lpType); }
+ BOOL IsValid() { return (m_fValid); }
+ void GetClsID(GUID *pgClsID) { *pgClsID = m_gClsID; }
+ HRESULT GetAPOInterfaces
+ (
+ IAudioProcessingObject **pIAPO,
+ IAudioProcessingObjectRT **pIAPORT,
+ IAudioProcessingObjectConfiguration **pIAPOConfig
+ );
+ IUnknown *GetObject() { return ((IUnknown*)m_pIUnknown.get()); }
+ IMMDevice *GetEndpoint() { return m_pIEndpoint.get(); }
+ IPropertyStore *GetEndpointStore() { return m_pIEPStore.get(); }
+ IPropertyStore *GetFxStore() { return m_pIFXStore.get(); }
+ IMMDeviceCollection *GetDeviceCollection() { return m_pIDevCollection.get(); }
+ UINT GetSoftwareIoDeviceInCollection() { return m_nSoftwareIoDeviceInCollection; }
+ UINT GetSoftwareIoConnectorIndex() { return m_nSoftwareIoConnectorIndex; }
+ PAPO_REG_PROPERTIES GetProperties() { return (m_pRegProps); }
+ LPSTR GetAttachedDevice() { return (LPSTR)(m_szAttachedDevice.get()); }
+ BOOL IsProxyApo() { return m_bProxyAPO; }
+
+ BOOL m_fSelected; // if TRUE, this device will be selected
+ wil::unique_cotaskmem_string m_szEndpoint;
+ wil::unique_cotaskmem_string m_sApoName;
+ wil::unique_cotaskmem_string m_sApoTypeName;
+
+ private:
+ BOOL m_fValid;
+ GUID m_gClsID;
+ wil::com_ptr_nothrow<IUnknown> m_pIUnknown;
+ wil::com_ptr_nothrow<IAudioProcessingObject> m_pIAPO;
+ PAPO_REG_PROPERTIES m_pRegProps;
+
+ // These are only used for SysFx
+ wil::com_ptr_nothrow<IMMDevice> m_pIEndpoint;
+ wil::unique_cotaskmem_string m_szAttachedDevice;
+ wil::com_ptr_nothrow<IPropertyStore> m_pIEPStore;
+ wil::com_ptr_nothrow<IPropertyStore> m_pIFXStore;
+ wil::com_ptr_nothrow<IMMDeviceCollection> m_pIDevCollection;
+ UINT m_nSoftwareIoDeviceInCollection;
+ UINT m_nSoftwareIoConnectorIndex;
+ BOOL m_bProxyAPO;
+ wil::unique_cotaskmem_string m_szPnPId; // a string that represents the PnPId (or other description) of the device under test
+ LPARAM m_lpType; // flags that will be intersected with test case flags
+};
+
+
+// ----------------------------------------------------------
+// Stores a list of APO devices on an endpoint pDevice
+// The list is populated using AddSysFxDevices and accessed
+// using m_DeviceList
+// ----------------------------------------------------------
+class CAPODeviceList
+{
+public:
+ CAPODeviceList();
+ ~CAPODeviceList(VOID);
+
+ HRESULT Initialize(wil::com_ptr_nothrow<IMMDevice> pDevice, LPWSTR deviceName);
+ HRESULT AddSysFxDevices();
+
+protected:
+ friend class CApoDeviceTests;
+
+ std::list<std::unique_ptr<CAPODevice>> m_DeviceList;
+ wil::com_ptr_nothrow<IMMDevice> m_spDevice;
+ WCHAR m_deviceName[MAX_PATH] = { '\0' };
+};
+
+class CApoDeviceTests : public WEX::TestClass<CApoDeviceTests>
+{
+ CApoDeviceTests(){};
+ ~CApoDeviceTests(){};
+
+ BEGIN_TEST_CLASS(CApoDeviceTests)
+ START_APPVERIFIFER
+ TEST_CLASS_PROPERTY(L"Owner", L"auddev")
+ TEST_CLASS_PROPERTY(L"TestClassification", L"Feature")
+ TEST_CLASS_PROPERTY(L"BinaryUnderTest", L"audiodg.exe")
+ TEST_CLASS_PROPERTY(L"ArtifactUnderTest", L"audioenginebaseapop.h")
+ TEST_CLASS_PROPERTY(L"ArtifactUnderTest", L"devicetopologyp.h")
+ TEST_CLASS_PROPERTY(L"RunAs", L"Elevated")
+ TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA")
+ TEST_CLASS_PROPERTY(L"Ignore", L"false")
+ END_APPVERIFIER
+ END_TEST_CLASS()
+
+ public:
+ TEST_METHOD_SETUP(setUpMethod);
+ TEST_METHOD_CLEANUP(tearDownMethod);
+
+ protected:
+ BEGIN_TEST_METHOD(TestAPOInitialize)
+ COMMON_ONECORE_TEST_PROPERTIES
+ TEST_METHOD_PROPERTY(L"Kits.TestId", L"ED37B03B-F091-4C8D-9EDD-FE7EC803BC8E")
+ TEST_METHOD_PROPERTY(L"Kits.TestId2", L"5B0F542E-719A-4949-A9DF-F8BBAC0E9912")
+ TEST_METHOD_PROPERTY(L"Kits.TestName", L"Audio APO - Verify APO Initializes - TestAPOInitialize")
+ TEST_METHOD_PROPERTY(L"Kits.ExpectedRuntime", L"1")
+ TEST_METHOD_PROPERTY(L"Kits.TimeoutInMinutes", L"5")
+ TEST_METHOD_PROPERTY(L"Kits.Description", L"Third Party APO Test: TestAPOInitialize")
+ APO_TEST_PROPERTIES
+ END_TEST_METHOD()
+
+ BEGIN_TEST_METHOD(TestCustomFormatSupport)
+ COMMON_ONECORE_TEST_PROPERTIES
+ TEST_METHOD_PROPERTY(L"Kits.TestId", L"571BD021-64F5-4CD1-9BA4-8ABD0857025F")
+ TEST_METHOD_PROPERTY(L"Kits.TestId2", L"EB313E34-CD9D-410B-9C6F-E7032C74F4D1")
+ TEST_METHOD_PROPERTY(L"Kits.TestName", L"Audio APO - Verify All Formats on Device are Valid - TestCustomFormatSupport")
+ TEST_METHOD_PROPERTY(L"Kits.ExpectedRuntime", L"1")
+ TEST_METHOD_PROPERTY(L"Kits.TimeoutInMinutes", L"5")
+ TEST_METHOD_PROPERTY(L"Kits.Description", L"Third Party APO Test: TestCustomFormatSupport")
+ APO_TEST_PROPERTIES
+ END_TEST_METHOD()
+
+ BEGIN_TEST_METHOD(TestValidFrameCount)
+ COMMON_ONECORE_TEST_PROPERTIES
+ TEST_METHOD_PROPERTY(L"Kits.TestId", L"B9E9F61A-2882-4256-ABA8-D57A46E54B76")
+ TEST_METHOD_PROPERTY(L"Kits.TestId2", L"ABE4D880-7F1A-434C-A7B9-248FFA96D2CF")
+ TEST_METHOD_PROPERTY(L"Kits.TestName", L"Audio APO - Verify Frame Count is Valid - TestValidFrameCount")
+ TEST_METHOD_PROPERTY(L"Kits.ExpectedRuntime", L"1")
+ TEST_METHOD_PROPERTY(L"Kits.TimeoutInMinutes", L"5")
+ TEST_METHOD_PROPERTY(L"Kits.Description", L"Third Party APO Test: TestValidFrameCount")
+ APO_TEST_PROPERTIES
+ END_TEST_METHOD()
+
+ BEGIN_TEST_METHOD(TestAPODataStreaming)
+ COMMON_ONECORE_TEST_PROPERTIES
+ TEST_METHOD_PROPERTY(L"Kits.TestId", L"D327B019-99E4-41BD-BF66-AF1A92801DAC")
+ TEST_METHOD_PROPERTY(L"Kits.TestId2", L"9EBF7FC3-7ADB-49A1-B0E0-C7501841E05A")
+ TEST_METHOD_PROPERTY(L"Kits.TestName", L"Audio APO - Verify APO Streams Data - TestAPODataStreaming")
+ TEST_METHOD_PROPERTY(L"Kits.ExpectedRuntime", L"1")
+ TEST_METHOD_PROPERTY(L"Kits.TimeoutInMinutes", L"5")
+ TEST_METHOD_PROPERTY(L"Kits.Description", L"Third Party APO Test: TestAPODataStreaming")
+ APO_TEST_PROPERTIES
+ END_TEST_METHOD()
+
+ BEGIN_TEST_METHOD(TestActivateDeactivate)
+ COMMON_ONECORE_TEST_PROPERTIES
+ TEST_METHOD_PROPERTY(L"Kits.TestId", L"D1C21041-9080-4990-B6A2-5F718649A3F2")
+ TEST_METHOD_PROPERTY(L"Kits.TestId2", L"F0556EDA-4757-409F-AE89-C5C1B0E31A84")
+ TEST_METHOD_PROPERTY(L"Kits.TestName", L"Audio APO - Verify Proper APO Activation and Deactivation - TestActivateDeactivate")
+ TEST_METHOD_PROPERTY(L"Kits.ExpectedRuntime", L"1")
+ TEST_METHOD_PROPERTY(L"Kits.TimeoutInMinutes", L"5")
+ TEST_METHOD_PROPERTY(L"Kits.Description", L"Third Party APO Test: TestActivateDeactivate")
+ APO_TEST_PROPERTIES
+ END_TEST_METHOD()
+
+ private:
+ std::list<std::unique_ptr<CAPODeviceList>> m_testDeviceWrapperList;
+};
+
+BEGIN_MODULE()
+ MODULE_PROPERTY(L"EtwLogger:WPRProfileFile", L"Audio-Tests.wprp")
+ MODULE_PROPERTY(L"EtwLogger:WPRProfile", L"MultimediaCategory.Verbose.File")
+END_MODULE()
diff --git a/audio/tests/HLK/ThirdPartyApoTests/APOOSUpgradeTest.cpp b/audio/tests/HLK/ThirdPartyApoTests/APOOSUpgradeTest.cpp
new file mode 100644
index 00000000..9fc5ae45
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/APOOSUpgradeTest.cpp
@@ -0,0 +1,96 @@
+#include <stdafx.h>
+
+#include <initguid.h>
+#include "propkey.h"
+#include <AudioClient.h>
+#include <SpatialAudioClient.h>
+#include <functiondiscoverykeys.h>
+#include <DevPKey.h>
+#include <AudioEngineBaseAPOP.h>
+#include "TestMediaType.h"
+#include <audioenginebaseapo.h>
+#include <MMDeviceAPI.h>
+#include <MMDeviceAPIP.h>
+
+#include <WexTestClass.h>
+
+#include <list>
+#include <memory>
+#include <ctime>
+#include <thread>
+#include <future>
+#include <mutex>
+#include <functional>
+#include <atlbase.h>
+
+#include "APOOSUpgradeTest.h"
+#include "APOStressTest.h"
+#include "sinewave.h"
+
+using namespace std;
+using namespace wil;
+using namespace WEX::Logging;
+using namespace WEX::Common;
+
+#define IF_FAILED_RETURN(hr) { HRESULT hrCode = hr; if(FAILED(hrCode)) { return hrCode; } }
+#define IF_SUCCEEDED(hr) { HRESULT hrCode = hr; if (!(hrCode == S_OK || hrCode == AUDCLNT_E_WRONG_ENDPOINT_TYPE)) { VERIFY_SUCCEEDED(hrCode); } }
+
+bool SetupSkipRTHeap();
+bool CleanupSkipRTHeap();
+
+bool CAPOUpgradeTest::setUpMethod()
+{
+ return SetupSkipRTHeap();
+}
+
+bool CAPOUpgradeTest::tearDownMethod()
+{
+ return CleanupSkipRTHeap();
+}
+
+void CAPOUpgradeTest::TestUpgrade()
+{
+ UINT cDevices = 0;
+ com_ptr_nothrow<IMMDeviceEnumerator> spEnumerator;
+ com_ptr_nothrow<IMMDeviceCollection> spDevices;
+
+ VERIFY_SUCCEEDED(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, IID_PPV_ARGS(&spEnumerator)));
+ VERIFY_SUCCEEDED(spEnumerator->EnumAudioEndpoints(eAll, DEVICE_STATE_ACTIVE, &spDevices));
+ VERIFY_SUCCEEDED(spDevices->GetCount(&cDevices));
+
+ for (UINT i = 0; i < cDevices; i++)
+ {
+ com_ptr_nothrow<IMMDevice> pDevice = nullptr;
+ com_ptr_nothrow<IAudioClient2> pAudioClient = nullptr;
+ com_ptr_nothrow<IMMEndpoint> pEndpoint = nullptr;
+ BOOL bOffloadCapable = FALSE;
+ EDataFlow eFlow = eAll;
+
+ VERIFY_SUCCEEDED(spDevices->Item(i, &pDevice));
+
+ VERIFY_SUCCEEDED(com_query_to_nothrow(pDevice, &pEndpoint));
+ VERIFY_SUCCEEDED(pEndpoint->GetDataFlow(&eFlow));
+
+ VERIFY_SUCCEEDED(pDevice->Activate(__uuidof(IAudioClient2), CLSCTX_ALL, NULL, (void**)&pAudioClient));
+ VERIFY_SUCCEEDED(pAudioClient->IsOffloadCapable(AudioCategory_Media, &bOffloadCapable));
+
+ if (eFlow == eAll || eFlow == eRender)
+ {
+ VERIFY_SUCCEEDED(BasicAudioStreaming(pDevice.get()));
+
+ VERIFY_SUCCEEDED(BasicSpatialAudio(pDevice.get()));
+
+ VERIFY_SUCCEEDED(BasicAudioLoopback(pDevice.get()));
+
+ if (bOffloadCapable)
+ {
+ VERIFY_SUCCEEDED(BasicOffloadStreaming(pDevice.get()));
+ }
+ }
+
+ if (eFlow == eAll || eFlow == eCapture)
+ {
+ VERIFY_SUCCEEDED(BasicAudioCapture(pDevice.get()));
+ }
+ }
+}
diff --git a/audio/tests/HLK/ThirdPartyApoTests/APOOSUpgradeTest.h b/audio/tests/HLK/ThirdPartyApoTests/APOOSUpgradeTest.h
new file mode 100644
index 00000000..3c61390d
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/APOOSUpgradeTest.h
@@ -0,0 +1,38 @@
+#include <stdafx.h>
+
+class CAPOUpgradeTest
+{
+ CAPOUpgradeTest(){};
+ ~CAPOUpgradeTest(){};
+
+ BEGIN_TEST_CLASS(CAPOUpgradeTest)
+ START_OSUPGRADE
+ START_APPVERIFIFER_UPGRADE
+ TEST_CLASS_PROPERTY(L"Owner", L"auddev")
+ TEST_CLASS_PROPERTY(L"TestClassification", L"Feature")
+ TEST_CLASS_PROPERTY(L"BinaryUnderTest", L"audiodg.exe")
+ TEST_CLASS_PROPERTY(L"ArtifactUnderTest", L"audioenginebaseapop.h")
+ TEST_CLASS_PROPERTY(L"RunAs", L"Elevated")
+ TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA")
+ TEST_CLASS_PROPERTY(L"Ignore", L"false")
+ TEST_CLASS_PROPERTY(L"EtwLogger:WPRProfileFile", L"Audio-Tests.wprp")
+ TEST_CLASS_PROPERTY(L"EtwLogger:WPRProfile", L"MultimediaCategory.Verbose.File")
+ END_APPVERIFIER
+ END_TEST_CLASS()
+
+public:
+ TEST_METHOD_SETUP(setUpMethod);
+ TEST_METHOD_CLEANUP(tearDownMethod);
+
+protected:
+ BEGIN_TEST_METHOD(TestUpgrade)
+ COMMON_ONECORE_TEST_PROPERTIES
+ TEST_METHOD_PROPERTY(L"Kits.TestId", L"B98FD3CB-2E6E-4152-BA85-3021149B8E86")
+ TEST_METHOD_PROPERTY(L"Kits.TestId2", L"C467E942-EB43-477F-8E2A-01D07FEF90C4")
+ TEST_METHOD_PROPERTY(L"Kits.TestName", L"Audio APO - Verify APOs Work After an OS Upgrade - TestUpgrade")
+ TEST_METHOD_PROPERTY(L"Kits.ExpectedRuntime", L"60")
+ TEST_METHOD_PROPERTY(L"Kits.TimeoutInMinutes", L"240")
+ TEST_METHOD_PROPERTY(L"Kits.Description", L"Third Party APO Test: TestUpgrade")
+ APO_TEST_PROPERTIES
+ END_TEST_METHOD()
+}; \ No newline at end of file
diff --git a/audio/tests/HLK/ThirdPartyApoTests/APOStressTest.cpp b/audio/tests/HLK/ThirdPartyApoTests/APOStressTest.cpp
new file mode 100644
index 00000000..160f488b
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/APOStressTest.cpp
@@ -0,0 +1,777 @@
+#include <stdafx.h>
+
+#include <initguid.h>
+#include "propkey.h"
+#include <AudioClient.h>
+#include <SpatialAudioClient.h>
+#include <functiondiscoverykeys.h>
+#include <DevPKey.h>
+#include <AudioEngineBaseAPOP.h>
+#include "TestMediaType.h"
+#include <audioenginebaseapo.h>
+#include <MMDeviceAPI.h>
+#include <MMDeviceAPIP.h>
+
+#include <WexTestClass.h>
+
+#include <list>
+#include <memory>
+#include <ctime>
+#include <thread>
+#include <future>
+#include <mutex>
+#include <functional>
+#include <atlbase.h>
+
+#include "APOStressTest.h"
+#include "sinewave.h"
+#include "util.h"
+
+#include <psapi.h>
+#include <processthreadsapi.h>
+
+using namespace std;
+using namespace wil;
+using namespace WEX::Logging;
+using namespace WEX::Common;
+
+#define NUMBER_OF_TESTS 8
+#define THIRTY_MIN_IN_SEC 1800
+#define SIXTY_SECONDS 60
+#define ONE_SEC_IN_MS 1000
+#define THIRTY_MIN_IN_MS 1800000
+#define MAX_ALLOWED_PAGEFILE_USAGE_IN_BYTES 300000000
+
+#define IF_FAILED_RETURN(hr) { HRESULT hrCode = hr; if(FAILED(hrCode)) { return hrCode; } }
+
+#define REGKEY_AUDIOSERVICE L"Software\\Microsoft\\Windows\\CurrentVersion\\Audio"
+#define REGVALUE_SKIPRTHEAP L"SkipRTHeap"
+
+const DWORD WAIT_TIME_MIN_FOR_THREAD_OPERATION = 3u * 1000u; // 3 seconds
+const DWORD WAIT_TIME_MAX_FOR_THREAD_OPERATION = 10u * 1000u; // 10 seconds
+
+size_t maxAudioDGPagefileUsage = 0;
+std::mutex maxAudioDGPagefileUsage_mutex; // protects maxAudioDGPagefileUsage_mutex
+
+template <typename T>
+inline T RandInRange(T min, T max)
+{
+ // Treat the value span as a double right away. Otherwise if min = 0, and max
+ // is truly the max for the type, the value span could loop to zero.
+ double valueSpan = 1.0f + (double) (max - min);
+
+ // The following had a problem where doubles larger than 0x8000000000000000 were always truncating
+ // to 0x8000000000000000 when cast to a DWORD64. Multiplying by 0.5f and then (T) 2 seemed to
+ // get around this problem.
+ //return min + (T) ((double) (max - min + 1) * (double) rand() / (double) (RAND_MAX + 1));
+
+ // Then the following had a problem where RandInRange(0, 1) could never return 1.
+ //return min + (T) 2 * (T) (0.5f * valueSpan * ((double) rand() / (double) (RAND_MAX + 1)));
+
+ double offset = valueSpan * ((double) rand() / (double) (RAND_MAX + 1));
+
+ if (offset > (double) ((DWORD64) 0x8000000000000000))
+ {
+ return min + (T) 2 * (T) (0.5f * offset);
+ }
+
+ return min + (T) offset;
+}
+
+void WriteToAudioObjectBuffer(FLOAT* buffer, UINT frameCount, FLOAT frequency, UINT samplingRate)
+{
+ const double PI = 4 * atan2(1.0, 1.0);
+ static double _radPhase = 0.0;
+ double step = 2 * PI * frequency / samplingRate;
+
+ for (UINT i = 0; i < frameCount; i++)
+ {
+ double sample = sin(_radPhase);
+ buffer[i] = FLOAT(sample);
+ _radPhase += step; // next frame phase
+
+ if (_radPhase >= 2 * PI)
+ {
+ _radPhase -= 2 * PI;
+ }
+ }
+}
+
+bool SetupSkipRTHeap()
+{
+ DWORD dwValue = 1;
+ DWORD cbData = sizeof(dwValue);
+
+ DWORD result = RegSetKeyValueW(HKEY_LOCAL_MACHINE, REGKEY_AUDIOSERVICE, REGVALUE_SKIPRTHEAP, REG_DWORD, &dwValue, cbData);
+
+ RestartAudioService();
+
+ return (result == ERROR_SUCCESS);
+}
+
+bool CleanupSkipRTHeap()
+{
+ DWORD result = RegDeleteKeyValueW(HKEY_LOCAL_MACHINE, REGKEY_AUDIOSERVICE, REGVALUE_SKIPRTHEAP);
+
+ RestartAudioService();
+
+ return (result == ERROR_SUCCESS);
+}
+
+bool CAPOStressTest::setUpMethod()
+{
+ return SetupSkipRTHeap();
+}
+
+bool CAPOStressTest::tearDownMethod()
+{
+ return CleanupSkipRTHeap();
+}
+
+void CAPOStressTest::AudioAPOStressTest()
+{
+
+ UINT cDevices = 0;
+ com_ptr_nothrow<IMMDeviceEnumerator> spEnumerator;
+ com_ptr_nothrow<IMMDeviceCollection> spDevices;
+ vector<com_ptr<IMMDevice>> sEndpoints;
+
+ VERIFY_SUCCEEDED(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, IID_PPV_ARGS(&spEnumerator)));
+ VERIFY_SUCCEEDED(spEnumerator->EnumAudioEndpoints(eAll, DEVICE_STATE_ACTIVE, &spDevices));
+ VERIFY_SUCCEEDED(spDevices->GetCount(&cDevices));
+
+ for (UINT i = 0; i < cDevices; i++)
+ {
+ wil::com_ptr<IMMDevice> pEndpoint = nullptr;
+
+ VERIFY_SUCCEEDED(spDevices->Item(i, &pEndpoint));
+
+ sEndpoints.push_back(pEndpoint);
+ }
+
+ RunStressTest(THIRTY_MIN_IN_SEC, sEndpoints);
+}
+
+std::wstring QueryProcessName(const DWORD pid)
+{
+ wil::unique_handle hProcess(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid));
+ if(NULL == hProcess)
+ {
+ return L"err " + std::to_wstring(GetLastError());
+ }
+ else
+ {
+ WCHAR szProcessName[1024];
+ DWORD cchSize = ARRAYSIZE(szProcessName);
+ if (0 == QueryFullProcessImageNameW(hProcess.get(), 0, szProcessName, &cchSize))
+ {
+ return L"err " + std::to_wstring(GetLastError());
+ }
+
+ PWSTR fileName = szProcessName + cchSize;
+ while (fileName != szProcessName && *fileName != L'\\') fileName--;
+
+ return (*fileName == L'\\') ? fileName + 1 : fileName;
+ }
+}
+
+DWORD GetAudioDGProcessID()
+{
+ // Get the list of process identifiers.
+
+ DWORD aProcesses[1024], cbNeeded, cProcesses;
+ unsigned int i;
+
+ if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
+ {
+ return 0;
+ }
+
+ // Calculate how many process identifiers were returned.
+
+ cProcesses = cbNeeded / sizeof(DWORD);
+
+ // Look for AudioDG name and process identifier on each process.
+
+ for ( i = 0; i < cProcesses; i++ )
+ {
+ if( aProcesses[i] != 0 && 0 == _wcsicmp(QueryProcessName(aProcesses[i]).c_str(), L"AUDIODG.EXE"))
+ {
+ return aProcesses[i];
+ }
+ }
+
+ return 0;
+}
+
+void GetAudioDGMemoryUsageSample()
+{
+ // Get the AudioDG process ID
+ DWORD audioDGProcessID = GetAudioDGProcessID();
+
+ if (audioDGProcessID != 0)
+ {
+ std::lock_guard<std::mutex> autoLock(maxAudioDGPagefileUsage_mutex);
+
+ // Memory PagefileUsage snapshot
+ PROCESS_MEMORY_COUNTERS pmc;
+
+ HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
+ PROCESS_VM_READ,
+ FALSE, audioDGProcessID );
+
+ if (hProcess != NULL && GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc)) )
+ {
+ maxAudioDGPagefileUsage = max(maxAudioDGPagefileUsage, pmc.PagefileUsage);
+ }
+
+ VERIFY_IS_TRUE(maxAudioDGPagefileUsage < MAX_ALLOWED_PAGEFILE_USAGE_IN_BYTES);
+
+ CloseHandle( hProcess );
+ }
+ else
+ {
+ Log::Warning(L"Unable to find AudioDG PID");
+ }
+}
+
+HRESULT BasicAudioStreaming(IMMDevice* pEndpoint)
+{
+ com_ptr_nothrow<IAudioClient2> pAudioClient;
+ wil::unique_cotaskmem_ptr<WAVEFORMATEX> mixFormat;
+
+ if (pEndpoint == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ IF_FAILED_RETURN(pEndpoint->Activate(__uuidof(IAudioClient2), CLSCTX_ALL, NULL, (void**)&pAudioClient));
+
+ AudioClientProperties clientProperties = { 0 };
+ clientProperties.cbSize = sizeof(AudioClientProperties);
+ clientProperties.bIsOffload = false;
+ clientProperties.eCategory = (AUDIO_STREAM_CATEGORY) RandInRange(0, 11);
+
+ IF_FAILED_RETURN(pAudioClient->SetClientProperties(&clientProperties));
+
+ IF_FAILED_RETURN(pAudioClient->GetMixFormat(wil::out_param_ptr<WAVEFORMATEX **>(mixFormat)));
+
+ IF_FAILED_RETURN(pAudioClient->Initialize(
+ AUDCLNT_SHAREMODE_SHARED,
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
+ 0,
+ 0,
+ mixFormat.get(),
+ nullptr));
+
+ com_ptr_nothrow<IAudioRenderClient> pRenderClient;
+ IF_FAILED_RETURN(pAudioClient->GetService(_uuidof(IAudioRenderClient), wil::out_param_ptr<void **>(pRenderClient)));
+
+ wil::unique_event bufferCompleteEvent;
+ bufferCompleteEvent.create();
+ IF_FAILED_RETURN(pAudioClient->SetEventHandle(bufferCompleteEvent.get()));
+
+ UINT32 bufferFrameCount;
+ REFERENCE_TIME duration = RandInRange(WAIT_TIME_MIN_FOR_THREAD_OPERATION, WAIT_TIME_MAX_FOR_THREAD_OPERATION);
+ IF_FAILED_RETURN(pAudioClient->GetBufferSize(&bufferFrameCount));
+
+ SineWave sw(mixFormat->nChannels, mixFormat->nSamplesPerSec);
+ for (unsigned i = 0; i < mixFormat->nChannels; ++i)
+ {
+ sw.SetChannel(i, 400, 0.25f);
+ }
+
+ BYTE* data{};
+ IF_FAILED_RETURN(pRenderClient->GetBuffer(bufferFrameCount, &data));
+
+ sw.FillFrames(data, bufferFrameCount);
+ IF_FAILED_RETURN(pRenderClient->ReleaseBuffer(bufferFrameCount, 0));
+
+ IF_FAILED_RETURN(pAudioClient->Start());
+
+ unsigned c = 0;
+ while (c++ < duration)
+ {
+ if (WaitForSingleObject(bufferCompleteEvent.get(), ONE_SEC_IN_MS) != WAIT_OBJECT_0)
+ {
+ break;
+ }
+
+ unsigned numFramesPadding{};
+ IF_FAILED_RETURN(pAudioClient->GetCurrentPadding(&numFramesPadding));
+ auto numFramesAvailable = bufferFrameCount - numFramesPadding;
+
+ IF_FAILED_RETURN(pRenderClient->GetBuffer(numFramesAvailable, &data));
+ sw.FillFrames(data, numFramesAvailable);
+ IF_FAILED_RETURN(pRenderClient->ReleaseBuffer(numFramesAvailable, 0));
+ }
+
+ // Get a sample of the current AudioDG memory usage
+ GetAudioDGMemoryUsageSample();
+
+ IF_FAILED_RETURN(pAudioClient->Stop());
+
+ return S_OK;
+}
+
+HRESULT DisableEnableEndpoint(IMMDevice* pEndpoint)
+{
+ com_ptr_nothrow<IMMEndpointManager> pManager = nullptr;
+
+ if (pEndpoint == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ IF_FAILED_RETURN(CoCreateInstance(__uuidof(MMEndpointManager), nullptr, CLSCTX_ALL, IID_PPV_ARGS(&pManager)));
+
+ IF_FAILED_RETURN(pManager->SetEndpointState(pEndpoint, DEVICE_STATE_DISABLED));
+
+ Sleep(1000);
+
+ IF_FAILED_RETURN(pManager->SetEndpointState(pEndpoint, DEVICE_STATE_ACTIVE));
+
+ return S_OK;
+}
+
+HRESULT BasicAudioCapture(IMMDevice* pEndpoint)
+{
+ com_ptr_nothrow<IAudioClient> pAudioClient;
+ wil::unique_cotaskmem_ptr<WAVEFORMATEX> mixFormat;
+
+ if (pEndpoint == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ IF_FAILED_RETURN(pEndpoint->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient));
+
+ IF_FAILED_RETURN(pAudioClient->GetMixFormat(wil::out_param_ptr<WAVEFORMATEX **>(mixFormat)));
+
+ IF_FAILED_RETURN(pAudioClient->Initialize(
+ AUDCLNT_SHAREMODE_SHARED,
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
+ 0,
+ 0,
+ mixFormat.get(),
+ nullptr));
+
+ com_ptr_nothrow<IAudioCaptureClient> pCaptureClient;
+ IF_FAILED_RETURN(pAudioClient->GetService(_uuidof(IAudioCaptureClient), wil::out_param_ptr<void **>(pCaptureClient)));
+
+ wil::unique_event bufferCompleteEvent;
+ bufferCompleteEvent.create();
+ IF_FAILED_RETURN(pAudioClient->SetEventHandle(bufferCompleteEvent.get()));
+
+ UINT32 bufferFrameCount;
+ REFERENCE_TIME duration = RandInRange(WAIT_TIME_MIN_FOR_THREAD_OPERATION, WAIT_TIME_MAX_FOR_THREAD_OPERATION);
+ IF_FAILED_RETURN(pAudioClient->GetBufferSize(&bufferFrameCount));
+
+ BYTE* data{};
+ DWORD dwFlags = 0;
+ UINT32 numFramesInNextPacket = 0;
+
+ IF_FAILED_RETURN(pCaptureClient->GetNextPacketSize(&numFramesInNextPacket));
+ IF_FAILED_RETURN(pCaptureClient->GetBuffer(&data, &numFramesInNextPacket, &dwFlags, NULL, NULL));
+
+ IF_FAILED_RETURN(pAudioClient->Start());
+
+ unsigned c = 0;
+ while (c++ < duration)
+ {
+ if (WaitForSingleObject(bufferCompleteEvent.get(), ONE_SEC_IN_MS) != WAIT_OBJECT_0)
+ {
+ break;
+ }
+
+ IF_FAILED_RETURN(pCaptureClient->ReleaseBuffer(numFramesInNextPacket));
+
+ IF_FAILED_RETURN(pCaptureClient->GetBuffer(&data, &numFramesInNextPacket, &dwFlags, NULL, NULL));
+ }
+
+ // Get a sample of the current AudioDG memory usage
+ GetAudioDGMemoryUsageSample();
+
+ IF_FAILED_RETURN(pAudioClient->Stop());
+
+ return S_OK;
+}
+
+HRESULT BasicAudioLoopback(IMMDevice* pEndpoint)
+{
+ com_ptr_nothrow<IAudioClient> pAudioClient;
+ wil::unique_cotaskmem_ptr<WAVEFORMATEX> mixFormat;
+
+ if (pEndpoint == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ IF_FAILED_RETURN(pEndpoint->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient));
+
+ IF_FAILED_RETURN(pAudioClient->GetMixFormat(wil::out_param_ptr<WAVEFORMATEX **>(mixFormat)));
+
+ IF_FAILED_RETURN(pAudioClient->Initialize(
+ AUDCLNT_SHAREMODE_SHARED,
+ AUDCLNT_STREAMFLAGS_LOOPBACK | AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM,
+ 0,
+ 0,
+ mixFormat.get(),
+ nullptr));
+
+ com_ptr_nothrow<IAudioCaptureClient> pCaptureClient;
+ IF_FAILED_RETURN(pAudioClient->GetService(__uuidof(IAudioCaptureClient), wil::out_param_ptr<void **>(pCaptureClient)));
+
+ wil::unique_event bufferCompleteEvent;
+ bufferCompleteEvent.create();
+ IF_FAILED_RETURN(pAudioClient->SetEventHandle(bufferCompleteEvent.get()));
+
+ UINT32 bufferFrameCount;
+ IF_FAILED_RETURN(pAudioClient->GetBufferSize(&bufferFrameCount));
+
+ BYTE* data{};
+ DWORD dwFlags = 0;
+ UINT32 numFramesInNextPacket = 0;
+
+ IF_FAILED_RETURN(pCaptureClient->GetNextPacketSize(&numFramesInNextPacket));
+
+ IF_FAILED_RETURN(pAudioClient->Start());
+
+ while (numFramesInNextPacket != 0)
+ {
+ IF_FAILED_RETURN(pCaptureClient->GetBuffer(&data, &numFramesInNextPacket, &dwFlags, NULL, NULL));
+
+ IF_FAILED_RETURN(pCaptureClient->ReleaseBuffer(numFramesInNextPacket));
+
+ IF_FAILED_RETURN(pCaptureClient->GetNextPacketSize(&numFramesInNextPacket));
+ }
+
+ // Get a sample of the current AudioDG memory usage
+ GetAudioDGMemoryUsageSample();
+
+ IF_FAILED_RETURN(pAudioClient->Stop());
+
+ return S_OK;
+}
+
+HRESULT BasicSpatialAudio(IMMDevice* pEndpoint)
+{
+#ifdef LNM
+ EnableSpatialAudio();
+#endif
+
+ if (pEndpoint == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ com_ptr_nothrow<ISpatialAudioClient> client;
+ IF_FAILED_RETURN(pEndpoint->Activate(__uuidof(ISpatialAudioClient), CLSCTX_ALL, nullptr, wil::out_param_ptr<void **>(client)));
+
+ com_ptr_nothrow<IAudioFormatEnumerator> enumer;
+ IF_FAILED_RETURN(client->GetSupportedAudioObjectFormatEnumerator(&enumer));
+
+ wil::unique_cotaskmem_ptr<WAVEFORMATEX> fmt;
+ IF_FAILED_RETURN(enumer->GetFormat(0, wil::out_param_ptr<WAVEFORMATEX **>(fmt)));
+
+ unique_event event;
+ event.create();
+ if (event == nullptr)
+ {
+ HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ unique_prop_variant pv;
+ auto params = reinterpret_cast<SpatialAudioObjectRenderStreamActivationParams *>(CoTaskMemAlloc(sizeof(SpatialAudioObjectRenderStreamActivationParams)));
+ *params = SpatialAudioObjectRenderStreamActivationParams{fmt.get(), (AudioObjectType)AudioObjectType_FrontLeft, 0, 0, AudioCategory_Other, event.get(), nullptr};
+ pv.vt = VT_BLOB;
+ pv.blob.cbSize = sizeof(*params);
+ pv.blob.pBlobData = reinterpret_cast<BYTE *>(params);
+
+ com_ptr_nothrow<ISpatialAudioObjectRenderStream> stream;
+ IF_FAILED_RETURN(client->ActivateSpatialAudioStream(&pv, __uuidof(ISpatialAudioObjectRenderStream), wil::out_param_ptr<void **>(stream)));
+
+ com_ptr_nothrow<ISpatialAudioObject> audioObjectFrontLeft;
+ IF_FAILED_RETURN(stream->ActivateSpatialAudioObject(AudioObjectType_FrontLeft, &audioObjectFrontLeft));
+
+ IF_FAILED_RETURN(stream->Start());
+
+ UINT totalFrameCount = fmt->nSamplesPerSec * 2;
+
+ bool isRendering = true;
+ while (isRendering)
+ {
+ // Wait for a signal from the audio-engine to start the next processing pass
+ if (WaitForSingleObject(event.get(), 100) != WAIT_OBJECT_0)
+ {
+ IF_FAILED_RETURN(stream->Reset());
+ }
+
+ UINT32 availableDynamicObjectCount = 0;
+ UINT32 frameCount = 0;
+
+ // Begin the process of sending object data and metadata
+ // Get the number of dynamic objects that can be used to send object-data
+ // Get the frame count that each buffer will be filled with
+ IF_FAILED_RETURN(stream->BeginUpdatingAudioObjects(&availableDynamicObjectCount, &frameCount));
+
+ BYTE* buffer = nullptr;
+ UINT32 bufferLength = 0;
+
+ if (audioObjectFrontLeft == nullptr)
+ {
+ IF_FAILED_RETURN(stream->ActivateSpatialAudioObject(AudioObjectType::AudioObjectType_FrontLeft, &audioObjectFrontLeft));
+ }
+
+ // Get the buffer to write audio data
+ IF_FAILED_RETURN(audioObjectFrontLeft->GetBuffer(&buffer, &bufferLength));
+
+ if (totalFrameCount >= frameCount)
+ {
+ // Write audio data to the buffer
+ WriteToAudioObjectBuffer(reinterpret_cast<float*>(buffer), frameCount, 200.0f, fmt->nSamplesPerSec);
+
+ totalFrameCount -= frameCount;
+ }
+ else
+ {
+ // Write audio data to the buffer
+ WriteToAudioObjectBuffer(reinterpret_cast<float*>(buffer), totalFrameCount, 750.0f, fmt->nSamplesPerSec);
+
+ // Get a sample of the current AudioDG memory usage
+ GetAudioDGMemoryUsageSample();
+
+ // Set end of stream for the last buffer
+ IF_FAILED_RETURN(audioObjectFrontLeft->SetEndOfStream(totalFrameCount));
+
+ audioObjectFrontLeft = nullptr; // Release the object
+
+ isRendering = false;
+ }
+
+ // Let the audio engine know that the object data are available for processing now
+ IF_FAILED_RETURN(stream->EndUpdatingAudioObjects());
+ }
+
+ return S_OK;
+}
+
+HRESULT BasicOffloadStreaming(IMMDevice* pEndpoint)
+{
+ com_ptr_nothrow<IAudioClient2> pAudioClient;
+ wil::unique_cotaskmem_ptr<WAVEFORMATEX> mixFormat;
+ BOOL bOffloadCapable = FALSE;
+
+ if (pEndpoint == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ IF_FAILED_RETURN(pEndpoint->Activate(__uuidof(IAudioClient2), CLSCTX_ALL, NULL, (void**)&pAudioClient));
+ IF_FAILED_RETURN(pAudioClient->IsOffloadCapable(AudioCategory_Media, &bOffloadCapable));
+
+ AudioClientProperties clientProperties = { 0 };
+ clientProperties.cbSize = sizeof(AudioClientProperties);
+ clientProperties.bIsOffload = bOffloadCapable ? true : false;
+ clientProperties.eCategory = AudioCategory_Media;
+
+ if (bOffloadCapable)
+ {
+ clientProperties.bIsOffload = true;
+ }
+
+ IF_FAILED_RETURN(pAudioClient->SetClientProperties(&clientProperties));
+
+ IF_FAILED_RETURN(pAudioClient->GetMixFormat(wil::out_param_ptr<WAVEFORMATEX **>(mixFormat)));
+
+ IF_FAILED_RETURN(pAudioClient->Initialize(
+ AUDCLNT_SHAREMODE_SHARED,
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
+ 0,
+ 0,
+ mixFormat.get(),
+ nullptr));
+
+ com_ptr_nothrow<IAudioRenderClient> pRenderClient;
+ IF_FAILED_RETURN(pAudioClient->GetService(_uuidof(IAudioRenderClient), wil::out_param_ptr<void **>(pRenderClient)));
+
+ wil::unique_event bufferCompleteEvent;
+ bufferCompleteEvent.create();
+ IF_FAILED_RETURN(pAudioClient->SetEventHandle(bufferCompleteEvent.get()));
+
+ UINT32 bufferFrameCount;
+ REFERENCE_TIME duration = RandInRange(WAIT_TIME_MIN_FOR_THREAD_OPERATION, WAIT_TIME_MAX_FOR_THREAD_OPERATION);
+ IF_FAILED_RETURN(pAudioClient->GetBufferSize(&bufferFrameCount));
+
+ SineWave sw(mixFormat->nChannels, mixFormat->nSamplesPerSec);
+ for (unsigned i = 0; i < mixFormat->nChannels; ++i)
+ {
+ sw.SetChannel(i, 400, 0.25f);
+ }
+
+ BYTE* data{};
+ IF_FAILED_RETURN(pRenderClient->GetBuffer(bufferFrameCount, &data));
+
+ sw.FillFrames(data, bufferFrameCount);
+ IF_FAILED_RETURN(pRenderClient->ReleaseBuffer(bufferFrameCount, 0));
+
+ IF_FAILED_RETURN(pAudioClient->Start());
+
+ unsigned c = 0;
+ while (c++ < duration)
+ {
+ if (WaitForSingleObject(bufferCompleteEvent.get(), ONE_SEC_IN_MS) != WAIT_OBJECT_0)
+ {
+ break;
+ }
+
+ unsigned numFramesPadding{};
+ IF_FAILED_RETURN(pAudioClient->GetCurrentPadding(&numFramesPadding));
+ auto numFramesAvailable = bufferFrameCount - numFramesPadding;
+
+ IF_FAILED_RETURN(pRenderClient->GetBuffer(numFramesAvailable, &data));
+ sw.FillFrames(data, numFramesAvailable);
+ IF_FAILED_RETURN(pRenderClient->ReleaseBuffer(numFramesAvailable, 0));
+ }
+
+ // Get a sample of the current AudioDG memory usage
+ GetAudioDGMemoryUsageSample();
+
+ IF_FAILED_RETURN(pAudioClient->Stop());
+
+ return S_OK;
+}
+
+void RunStressTest(int timeInSeconds, std::vector<wil::com_ptr<IMMDevice>>& pEndpoints)
+{
+ const UINT num = static_cast<UINT>(pEndpoints.size()) * NUMBER_OF_TESTS;
+
+ std::vector<std::thread> threads(num);
+
+ for (UINT i = 0; i < pEndpoints.size(); i++)
+ {
+ threads[i * NUMBER_OF_TESTS + 0] = std::thread([=](){
+ BasicAudioStreaming(pEndpoints[i].get());
+ });
+
+ threads[i * NUMBER_OF_TESTS + 1] = std::thread([=](){
+ BasicAudioStreaming(pEndpoints[i].get());
+ });
+
+ threads[i * NUMBER_OF_TESTS + 2] = std::thread([=](){
+ BasicAudioStreaming(pEndpoints[i].get());
+ });
+
+ threads[i * NUMBER_OF_TESTS + 3] = std::thread([=](){
+ BasicAudioCapture(pEndpoints[i].get());
+ });
+
+ threads[i * NUMBER_OF_TESTS + 4] = std::thread([=](){
+ BasicAudioLoopback(pEndpoints[i].get());
+ });
+
+ threads[i * NUMBER_OF_TESTS + 5] = std::thread([=](){
+ DisableEnableEndpoint(pEndpoints[i].get());
+ });
+
+ threads[i * NUMBER_OF_TESTS + 6] = std::thread([=](){
+ BasicSpatialAudio(pEndpoints[i].get());
+ });
+
+ threads[i * NUMBER_OF_TESTS + 7] = std::thread([=](){
+ BasicOffloadStreaming(pEndpoints[i].get());
+ });
+ }
+
+ time_t timer;
+ time(&timer);
+
+ time_t endTime = timer + timeInSeconds;
+
+ while (timer < endTime)
+ {
+ for (UINT i = 0; i < num; i++)
+ {
+ if (threads[i].joinable())
+ {
+ UINT testNumber = i % NUMBER_OF_TESTS;
+ UINT k = i / NUMBER_OF_TESTS;
+
+ threads[i].join();
+
+ switch (testNumber)
+ {
+ case 0:
+ threads[i] = std::thread([=]() {
+ Sleep(RandInRange(WAIT_TIME_MIN_FOR_THREAD_OPERATION, WAIT_TIME_MAX_FOR_THREAD_OPERATION));
+ BasicAudioStreaming(pEndpoints[k].get());
+ });
+ break;
+ case 1:
+ threads[i] = std::thread([=]() {
+ Sleep(RandInRange(WAIT_TIME_MIN_FOR_THREAD_OPERATION, WAIT_TIME_MAX_FOR_THREAD_OPERATION));
+ BasicAudioStreaming(pEndpoints[k].get());
+ });
+ break;
+ case 2:
+ threads[i] = std::thread([=]() {
+ Sleep(RandInRange(WAIT_TIME_MIN_FOR_THREAD_OPERATION, WAIT_TIME_MAX_FOR_THREAD_OPERATION));
+ BasicAudioStreaming(pEndpoints[k].get());
+ });
+ break;
+ case 3:
+ threads[i] = std::thread([=]() {
+ Sleep(RandInRange(WAIT_TIME_MIN_FOR_THREAD_OPERATION, WAIT_TIME_MAX_FOR_THREAD_OPERATION));
+ BasicAudioCapture(pEndpoints[k].get());
+ });
+ break;
+ case 4:
+ threads[i] = std::thread([=]() {
+ Sleep(RandInRange(WAIT_TIME_MIN_FOR_THREAD_OPERATION, WAIT_TIME_MAX_FOR_THREAD_OPERATION));
+ BasicAudioLoopback(pEndpoints[k].get());
+ });
+ break;
+ case 5:
+ threads[i] = std::thread([=]() {
+ Sleep(RandInRange(WAIT_TIME_MIN_FOR_THREAD_OPERATION, WAIT_TIME_MAX_FOR_THREAD_OPERATION));
+ DisableEnableEndpoint(pEndpoints[k].get());
+ });
+ break;
+ case 6:
+ threads[i] = std::thread([=]() {
+ Sleep(RandInRange(WAIT_TIME_MIN_FOR_THREAD_OPERATION, WAIT_TIME_MAX_FOR_THREAD_OPERATION));
+ BasicSpatialAudio(pEndpoints[k].get());
+ });
+ break;
+ case 7:
+ threads[i] = std::thread([=]() {
+ Sleep(RandInRange(WAIT_TIME_MIN_FOR_THREAD_OPERATION, WAIT_TIME_MAX_FOR_THREAD_OPERATION));
+ BasicOffloadStreaming(pEndpoints[k].get());
+ });
+ break;
+ }
+ }
+ }
+
+ time(&timer);
+ }
+
+ for (UINT j = 0; j < num; j++)
+ {
+ if (threads[j].joinable())
+ {
+ threads[j].join();
+ }
+ }
+
+ std::lock_guard<std::mutex> autoLock(maxAudioDGPagefileUsage_mutex);
+
+ // If we were not able to open the AudioDG handle process we should have 0 as memory usage
+ VERIFY_IS_TRUE(maxAudioDGPagefileUsage > 0);
+
+ // Adding the maxPagefileUsageValue to the VERIFY as a string
+ wchar_t maxAudioDGPagefileUsageString[32];
+ swprintf_s(maxAudioDGPagefileUsageString, L"%u", maxAudioDGPagefileUsage);
+
+ VERIFY_IS_TRUE(maxAudioDGPagefileUsage < MAX_ALLOWED_PAGEFILE_USAGE_IN_BYTES, maxAudioDGPagefileUsageString);
+} \ No newline at end of file
diff --git a/audio/tests/HLK/ThirdPartyApoTests/APOStressTest.h b/audio/tests/HLK/ThirdPartyApoTests/APOStressTest.h
new file mode 100644
index 00000000..07e74ea9
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/APOStressTest.h
@@ -0,0 +1,50 @@
+#include <stdafx.h>
+
+#define FIVE_MIN_IN_SEC 300
+
+class CAPOStressTest
+{
+ CAPOStressTest(){};
+ ~CAPOStressTest(){};
+
+ BEGIN_TEST_CLASS(CAPOStressTest)
+ START_APPVERIFIFER
+ TEST_CLASS_PROPERTY(L"Owner", L"auddev")
+ TEST_CLASS_PROPERTY(L"TestClassification", L"Feature")
+ TEST_CLASS_PROPERTY(L"BinaryUnderTest", L"audiodg.exe")
+ TEST_CLASS_PROPERTY(L"ArtifactUnderTest", L"audioenginebaseapop.h")
+ TEST_CLASS_PROPERTY(L"RunAs", L"System")
+ TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA")
+ TEST_CLASS_PROPERTY(L"Ignore", L"false")
+ TEST_CLASS_PROPERTY(L"EtwLogger:WPRProfileFile", L"Audio-Tests.wprp")
+ TEST_CLASS_PROPERTY(L"EtwLogger:WPRProfile", L"MultimediaCategory.Verbose.File")
+ END_APPVERIFIER
+ END_TEST_CLASS()
+
+public:
+ TEST_METHOD_SETUP(setUpMethod);
+ TEST_METHOD_CLEANUP(tearDownMethod);
+
+protected:
+ BEGIN_TEST_METHOD(AudioAPOStressTest)
+ COMMON_ONECORE_TEST_PROPERTIES
+ TEST_METHOD_PROPERTY(L"Kits.TestId", L"5C35BC8F-FAE1-434B-B842-6B58353696AB")
+ TEST_METHOD_PROPERTY(L"Kits.TestId2", L"1EB5F7F0-CA62-411E-9006-53A23F488332")
+ TEST_METHOD_PROPERTY(L"Kits.TestName", L"Audio APO - Stress the APO - AudioAPOStressTest")
+ TEST_METHOD_PROPERTY(L"Kits.ExpectedRuntime", L"30")
+ TEST_METHOD_PROPERTY(L"Kits.TimeoutInMinutes", L"60")
+ TEST_METHOD_PROPERTY(L"Kits.Description", L"Third Party APO Test: AudioAPOStressTest")
+ APO_TEST_PROPERTIES
+ END_TEST_METHOD()
+};
+
+HRESULT BasicAudioStreaming(IMMDevice *pEndpoint);
+HRESULT DisableEnableEndpoint(IMMDevice *pEndpoint);
+HRESULT BasicAudioCapture(IMMDevice *pEndpoint);
+HRESULT BasicAudioLoopback(IMMDevice *pEndpoint);
+HRESULT BasicSpatialAudio(IMMDevice *pEndpoint);
+HRESULT BasicOffloadStreaming(IMMDevice *pEndpoint);
+void RunStressTest(int timeInSeconds, std::vector<wil::com_ptr<IMMDevice>>& pEndpoints);
+
+bool SetupSkipRTHeap();
+bool CleanupSkipRTHeap(); \ No newline at end of file
diff --git a/audio/tests/HLK/ThirdPartyApoTests/CAPXHelper.cpp b/audio/tests/HLK/ThirdPartyApoTests/CAPXHelper.cpp
new file mode 100644
index 00000000..5600fb72
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/CAPXHelper.cpp
@@ -0,0 +1,247 @@
+#pragma once
+
+#include "CAPXHelper.h"
+
+bool IsCapXAPO(GUID clsid)
+{
+ bool bIsCapXAPO = false;
+
+ wil::com_ptr_nothrow<IAudioProcessingObject> apo;
+ if(SUCCEEDED(CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, __uuidof(IAudioProcessingObject), reinterpret_cast<void**>(&apo))))
+ {
+ wil::com_ptr_nothrow<IAudioSystemEffects3> capXAPO;
+ bIsCapXAPO = wil::try_com_query_to(apo, &capXAPO);
+ }
+
+ return bIsCapXAPO;
+}
+
+void GetClsidsFromVar(const PROPVARIANT& var, std::vector<GUID>& guids, _Outptr_ PWSTR* ppszFormattedClsids, std::vector<GUID>& capxGuids, _Outptr_ PWSTR* ppszCapXFormattedClsids)
+{
+ WCHAR formattedClsids[1024] = {};
+ PWSTR writeLocation = formattedClsids;
+ size_t remainingChars = ARRAYSIZE(formattedClsids);
+ const PWSTR formatSeparator = L"|%s";
+ bool bIsCapXAPO;
+ WCHAR capXformattedClsids[1024] = {};
+ PWSTR capXwriteLocation = capXformattedClsids;
+ size_t capXremainingChars = ARRAYSIZE(capXformattedClsids);
+
+ for (UINT i = 0; i < var.calpwstr.cElems; i++)
+ {
+ // populate vector
+ GUID clsid = {};
+ if (FAILED(CLSIDFromString(var.calpwstr.pElems[i], &clsid)))
+ {
+ return;
+ }
+
+ bIsCapXAPO = IsCapXAPO(clsid);
+ try
+ {
+ bIsCapXAPO ? capxGuids.push_back(clsid) : guids.push_back(clsid);
+ }
+ CATCH_LOG();
+
+ // build string to log
+ if (FAILED(bIsCapXAPO ? StringCchPrintfEx(capXwriteLocation, capXremainingChars, &capXwriteLocation, &capXremainingChars, 0, formatSeparator, var.calpwstr.pElems[i])
+ : StringCchPrintfEx(writeLocation, remainingChars, &writeLocation, &remainingChars, 0, formatSeparator, var.calpwstr.pElems[i])))
+ {
+ return;
+ }
+ }
+
+ wil::unique_cotaskmem_string spFormattedClsids = wil::make_cotaskmem_string_nothrow(formattedClsids+1);
+ if (spFormattedClsids)
+ {
+ *ppszFormattedClsids = spFormattedClsids.release();
+ }
+
+ wil::unique_cotaskmem_string spCapXFormattedClsids = wil::make_cotaskmem_string_nothrow(capXformattedClsids+1);
+ if (spCapXFormattedClsids)
+ {
+ *ppszCapXFormattedClsids = spCapXFormattedClsids.release();
+ }
+}
+
+
+bool EndpointContainsCapx(IMMDevice* pDevice)
+{
+ // some endpoints have an effects property store
+ // grab properties from that
+
+ GUID clsidSfx = {};
+ bool bIsCapXSfx = false;
+ GUID clsidMfx = {};
+ bool bIsCapXMfx = false;
+ GUID clsidEfx = {};
+ bool bIsCapXEfx = false;
+
+ // legacy drivers
+ GUID clsidLfx = {};
+ bool bIsCapXLfx = false;
+ GUID clsidGfx = {};
+ bool bIsCapXGfx = false;
+
+ // offload pin
+ GUID clsidOffloadSfx = {};
+ bool bIsCapXOffloadSfx = false;
+ GUID clsidOffloadMfx = {};
+ bool bIsCapXOffloadMfx = false;
+
+ // keyword spotter pin
+ GUID clsidKeywordSfx = {};
+ bool bIsCapXKeywordSfx = false;
+ GUID clsidKeywordMfx = {};
+ bool bIsCapXKeywordMfx = false;
+ GUID clsidKeywordEfx = {};
+ bool bIsCapXKeywordEfx = false;
+
+ // // composite effects
+ std::vector<GUID> clsidsCompositeSfx;
+ wil::unique_cotaskmem_string clsidsCompositeSfxStr;
+ std::vector<GUID> clsidsCompositeMfx;
+ wil::unique_cotaskmem_string clsidsCompositeMfxStr;
+ std::vector<GUID> clsidsCompositeEfx;
+ wil::unique_cotaskmem_string clsidsCompositeEfxStr;
+ // // CapX composite effects
+ std::vector<GUID> clsidsCapXCompositeSfx;
+ wil::unique_cotaskmem_string clsidsCapXCompositeSfxStr;
+ std::vector<GUID> clsidsCapXCompositeMfx;
+ wil::unique_cotaskmem_string clsidsCapXCompositeMfxStr;
+ std::vector<GUID> clsidsCapXCompositeEfx;
+ wil::unique_cotaskmem_string clsidsCapXCompositeEfxStr;
+
+ wil::com_ptr_nothrow<IMMEndpointInternal> spMMEndpointInternal;
+ if (wil::try_com_query_to(pDevice, &spMMEndpointInternal))
+ {
+ wil::com_ptr_nothrow<IPropertyStore> spFxProperties;
+ if ((S_OK == spMMEndpointInternal->TryOpenFXPropertyStore(STGM_READ, &spFxProperties)) && spFxProperties)
+ {
+ wil::unique_prop_variant varClsidSfx;
+ if (SUCCEEDED(spFxProperties->GetValue(PKEY_FX_StreamEffectClsid, &varClsidSfx)) && varClsidSfx.vt == VT_LPWSTR)
+ {
+ CLSIDFromString(varClsidSfx.pwszVal, &clsidSfx);
+ bIsCapXSfx = IsCapXAPO(clsidSfx);
+ }
+
+ wil::unique_prop_variant varClsidMfx;
+ if (SUCCEEDED(spFxProperties->GetValue(PKEY_FX_ModeEffectClsid, &varClsidMfx)) && varClsidMfx.vt == VT_LPWSTR)
+ {
+ CLSIDFromString(varClsidMfx.pwszVal, &clsidMfx);
+ bIsCapXMfx = IsCapXAPO(clsidMfx);
+ }
+
+ wil::unique_prop_variant varClsidEfx;
+ if (SUCCEEDED(spFxProperties->GetValue(PKEY_FX_EndpointEffectClsid, &varClsidEfx)) && varClsidEfx.vt == VT_LPWSTR)
+ {
+ CLSIDFromString(varClsidEfx.pwszVal, &clsidEfx);
+ bIsCapXEfx = IsCapXAPO(clsidEfx);
+ }
+
+ // legacy drivers
+ wil::unique_prop_variant varClsidLfx;
+ if (SUCCEEDED(spFxProperties->GetValue(PKEY_FX_PreMixEffectClsid, &varClsidLfx)) && varClsidLfx.vt == VT_LPWSTR)
+ {
+ CLSIDFromString(varClsidLfx.pwszVal, &clsidLfx);
+ bIsCapXLfx = IsCapXAPO(clsidLfx);
+ }
+
+ wil::unique_prop_variant varClsidGfx;
+ if (SUCCEEDED(spFxProperties->GetValue(PKEY_FX_PostMixEffectClsid, &varClsidGfx)) && varClsidGfx.vt == VT_LPWSTR)
+ {
+ CLSIDFromString(varClsidGfx.pwszVal, &clsidGfx);
+ bIsCapXGfx = IsCapXAPO(clsidGfx);
+ }
+
+ // offload
+ wil::unique_prop_variant varClsidOffloadSfx;
+ if (SUCCEEDED(spFxProperties->GetValue(PKEY_FX_Offload_StreamEffectClsid, &varClsidOffloadSfx)) && varClsidOffloadSfx.vt == VT_LPWSTR)
+ {
+ CLSIDFromString(varClsidOffloadSfx.pwszVal, &clsidOffloadSfx);
+ bIsCapXOffloadSfx = IsCapXAPO(clsidOffloadSfx);
+ }
+
+ wil::unique_prop_variant varClsidOffloadMfx;
+ if (SUCCEEDED(spFxProperties->GetValue(PKEY_FX_Offload_ModeEffectClsid, &varClsidOffloadMfx)) && varClsidOffloadMfx.vt == VT_LPWSTR)
+ {
+ CLSIDFromString(varClsidOffloadMfx.pwszVal, &clsidOffloadMfx);
+ bIsCapXOffloadMfx = IsCapXAPO(clsidOffloadMfx);
+ }
+
+ // keyword
+ wil::unique_prop_variant varClsidKeywordSfx;
+ if (SUCCEEDED(spFxProperties->GetValue(PKEY_FX_KeywordDetector_StreamEffectClsid, &varClsidKeywordSfx)) && varClsidKeywordSfx.vt == VT_LPWSTR)
+ {
+ CLSIDFromString(varClsidKeywordSfx.pwszVal, &clsidKeywordSfx);
+ bIsCapXKeywordSfx = IsCapXAPO(clsidKeywordSfx);
+ }
+
+ wil::unique_prop_variant varClsidKeywordMfx;
+ if (SUCCEEDED(spFxProperties->GetValue(PKEY_FX_KeywordDetector_ModeEffectClsid, &varClsidKeywordMfx)) && varClsidKeywordMfx.vt == VT_LPWSTR)
+ {
+ CLSIDFromString(varClsidKeywordMfx.pwszVal, &clsidKeywordMfx);
+ bIsCapXKeywordMfx = IsCapXAPO(clsidKeywordMfx);
+ }
+
+ wil::unique_prop_variant varClsidKeywordEfx;
+ if (SUCCEEDED(spFxProperties->GetValue(PKEY_FX_KeywordDetector_EndpointEffectClsid, &varClsidKeywordEfx)) && varClsidKeywordEfx.vt == VT_LPWSTR)
+ {
+ CLSIDFromString(varClsidKeywordEfx.pwszVal, &clsidKeywordEfx);
+ bIsCapXKeywordEfx = IsCapXAPO(clsidKeywordEfx);
+ }
+
+ // composite effects
+ wil::unique_prop_variant varClsidsCompositeSfx;
+ if (SUCCEEDED(spFxProperties->GetValue(PKEY_CompositeFX_StreamEffectClsid, &varClsidsCompositeSfx))
+ && varClsidsCompositeSfx.vt == (VT_VECTOR | VT_LPWSTR)
+ && varClsidsCompositeSfx.calpwstr.cElems > 0)
+ {
+ GetClsidsFromVar(varClsidsCompositeSfx, clsidsCompositeSfx, &clsidsCompositeSfxStr, clsidsCapXCompositeSfx, &clsidsCapXCompositeSfxStr);
+ }
+
+ wil::unique_prop_variant varClsidsCompositeMfx;
+ if (SUCCEEDED(spFxProperties->GetValue(PKEY_CompositeFX_ModeEffectClsid, &varClsidsCompositeMfx))
+ && varClsidsCompositeMfx.vt == (VT_VECTOR | VT_LPWSTR)
+ && varClsidsCompositeMfx.calpwstr.cElems > 0)
+ {
+ GetClsidsFromVar(varClsidsCompositeMfx, clsidsCompositeMfx, &clsidsCompositeMfxStr, clsidsCapXCompositeMfx, &clsidsCapXCompositeMfxStr);
+ }
+
+ wil::unique_prop_variant varClsidsCompositeEfx;
+ if (SUCCEEDED(spFxProperties->GetValue(PKEY_CompositeFX_EndpointEffectClsid, &varClsidsCompositeEfx))
+ && varClsidsCompositeEfx.vt == (VT_VECTOR | VT_LPWSTR)
+ && varClsidsCompositeEfx.calpwstr.cElems > 0)
+ {
+ GetClsidsFromVar(varClsidsCompositeEfx, clsidsCompositeEfx, &clsidsCompositeEfxStr, clsidsCapXCompositeEfx, &clsidsCapXCompositeEfxStr);
+ }
+ }
+ }
+
+ return ( bIsCapXSfx || bIsCapXMfx || bIsCapXEfx || bIsCapXLfx || bIsCapXGfx ||
+ bIsCapXOffloadSfx || bIsCapXOffloadMfx || bIsCapXKeywordSfx || bIsCapXKeywordMfx || bIsCapXKeywordEfx ||
+ clsidsCapXCompositeSfx.size() > 0 || clsidsCapXCompositeMfx.size() > 0 || clsidsCapXCompositeMfx.size() > 0 );
+}
+
+void EndpointsWithCapx(std::vector<wil::com_ptr<IMMDevice>>& capxEndpoints)
+{
+ UINT cDevices = 0;
+ com_ptr_nothrow<IMMDeviceEnumerator> spEnumerator;
+ com_ptr_nothrow<IMMDeviceCollection> spDevices;
+
+ VERIFY_SUCCEEDED(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, IID_PPV_ARGS(&spEnumerator)));
+ VERIFY_SUCCEEDED(spEnumerator->EnumAudioEndpoints(eAll, DEVICE_STATE_ACTIVE, &spDevices));
+ VERIFY_SUCCEEDED(spDevices->GetCount(&cDevices));
+
+ for (UINT i = 0; i < cDevices; i++)
+ {
+ wil::com_ptr<IMMDevice> pEndpoint = nullptr;
+
+ VERIFY_SUCCEEDED(spDevices->Item(i, &pEndpoint));
+
+ if (EndpointContainsCapx(pEndpoint.get()))
+ {
+ capxEndpoints.push_back(pEndpoint.get());
+ }
+ }
+} \ No newline at end of file
diff --git a/audio/tests/HLK/ThirdPartyApoTests/CAPXHelper.h b/audio/tests/HLK/ThirdPartyApoTests/CAPXHelper.h
new file mode 100644
index 00000000..62a5807e
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/CAPXHelper.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <stdafx.h>
+
+#include <wil\resultmacros.h>
+#include <wil\com.h>
+#include <audioclient.h>
+#include <audioclientp.h>
+#include <audiosessiontypesp.h>
+#include <mmdeviceapi.h>
+#include <mmdeviceapip.h>
+#include <endpointvolume.h>
+#include "etwlistener.h"
+#include <functiondiscoverykeys.h>
+#include <slpublic.h>
+
+#include <DevPKey.h>
+#include <AudioEngineBaseAPOP.h>
+#include "TestMediaType.h"
+#include <audioenginebaseapo.h>
+
+#include <list>
+#include <memory>
+
+using namespace std;
+using namespace wil;
+using namespace WEX::Logging;
+using namespace WEX::Common;
+
+bool IsCapXAPO(GUID clsid);
+void GetClsidsFromVar(const PROPVARIANT& var, std::vector<GUID>& guids, _Outptr_ PWSTR* ppszFormattedClsids, std::vector<GUID>& capxGuids, _Outptr_ PWSTR* ppszCapXFormattedClsids);
+bool EndpointContainsCapx(IMMDevice* pDevice);
+void EndpointsWithCapx(std::vector<wil::com_ptr<IMMDevice>>& capxEndpoints); \ No newline at end of file
diff --git a/audio/tests/HLK/ThirdPartyApoTests/CAPXLoggingFrameworkTests.cpp b/audio/tests/HLK/ThirdPartyApoTests/CAPXLoggingFrameworkTests.cpp
new file mode 100644
index 00000000..85f14ad8
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/CAPXLoggingFrameworkTests.cpp
@@ -0,0 +1,160 @@
+#include "CAPXLoggingFrameworkTests.h"
+
+
+bool CAPOLoggingFrameworkTest::setUpMethod()
+{
+ SLGetWindowsInformationDWORD(POLICY_KERNEL_ONECORE_DEVICE_FAMILY_ID, &m_dwPlatform);
+
+ EndpointsWithCapx(m_capxEndpoints);
+
+ return SetupSkipRTHeap();
+}
+
+bool CAPOLoggingFrameworkTest::tearDownMethod()
+{
+ return CleanupSkipRTHeap();
+}
+
+using malloca_deleter = wil::function_deleter<decltype(&::_freea), ::_freea>;
+template <typename T>
+using unique_malloca_ptr = wistd::unique_ptr<T, malloca_deleter>;
+enum QueryState
+{
+ None = 0,
+ ApoLog = 1,
+ PumpYield = 2
+};
+
+class CEventParser : public IEtwEventHandler
+{
+public:
+ int GetCountOfAPOLogging() { return m_countOfAudioProcessingNotifications; }
+ bool WasRTTThreadDetected() { return m_bRTThreadDetected; }
+ DWORD GetCountOfCreateFiles() { return m_dCreateFilesCalled; }
+
+private:
+
+ int m_countOfAudioProcessingNotifications = 0;
+ DWORD m_dLastPid = 0;
+ DWORD m_dLastThreadId = 0;
+ DWORD m_dCreateFilesCalled = 0;
+ bool m_bRTThreadDetected = false;
+ QueryState m_currentState = QueryState::None;
+
+ std::wstring QueryProcessName(const DWORD pid)
+ {
+ wil::unique_handle hProcess(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid));
+ if(NULL == hProcess)
+ {
+ return L"err " + std::to_wstring(GetLastError());
+ }
+ else
+ {
+ WCHAR szProcessName[1024];
+ DWORD cchSize = ARRAYSIZE(szProcessName);
+ if (0 == QueryFullProcessImageNameW(hProcess.get(), 0, szProcessName, &cchSize))
+ {
+ return L"err " + std::to_wstring(GetLastError());
+ }
+
+ PWSTR fileName = szProcessName + cchSize;
+ while (fileName != szProcessName && *fileName != L'\\') fileName--;
+
+ return (*fileName == L'\\') ? fileName + 1 : fileName;
+ }
+ }
+
+ std::wstring QueryTraceLevel(PEVENT_RECORD pEventRecord)
+ {
+ UNREFERENCED_PARAMETER(pEventRecord);
+ return L"err";
+ }
+
+ void OnEvent(PEVENT_RECORD pEventRecord)
+ {
+ WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
+ [&]() {
+ ULONG bufferSize = 0;
+ if (TdhGetEventInformation(pEventRecord, 0, nullptr, nullptr, &bufferSize) == ERROR_INSUFFICIENT_BUFFER)
+ {
+ unique_malloca_ptr<TRACE_EVENT_INFO> eventInfo(reinterpret_cast<PTRACE_EVENT_INFO>(_malloca(bufferSize)));
+ VERIFY_IS_NOT_NULL(eventInfo);
+ RETURN_IF_WIN32_ERROR(TdhGetEventInformation(pEventRecord, 0, nullptr, eventInfo.get(), &bufferSize));
+
+ // ApoLog is the name that the Logging framework uses for each of the logs sent through by the APO
+ if (_wcsicmp(L"ApoLog", reinterpret_cast<PWSTR>(reinterpret_cast<BYTE *>(eventInfo.get()) + eventInfo->EventNameOffset)) == 0)
+ {
+ m_countOfAudioProcessingNotifications++;
+ if (m_currentState == QueryState::PumpYield)
+ {
+ if (m_dLastPid == pEventRecord->EventHeader.ProcessId &&
+ m_dLastThreadId == pEventRecord->EventHeader.ThreadId)
+ {
+ m_bRTThreadDetected = true;
+ }
+ }
+
+ m_dLastPid = pEventRecord->EventHeader.ProcessId;
+ m_dLastThreadId = pEventRecord->EventHeader.ThreadId;
+ m_currentState = QueryState::ApoLog;
+ }
+ if (_wcsicmp(L"PumpYield", reinterpret_cast<PWSTR>(reinterpret_cast<BYTE *>(eventInfo.get()) + eventInfo->EventNameOffset)) == 0)
+ {
+ if (m_currentState == QueryState::ApoLog)
+ {
+ if (m_dLastPid == pEventRecord->EventHeader.ProcessId &&
+ m_dLastThreadId == pEventRecord->EventHeader.ThreadId)
+ {
+ m_bRTThreadDetected = true;
+ }
+ }
+
+ m_dLastPid = pEventRecord->EventHeader.ProcessId;
+ m_dLastThreadId = pEventRecord->EventHeader.ThreadId;
+ m_currentState = QueryState::PumpYield;
+ }
+ if (_wcsicmp(L"CreateFile", reinterpret_cast<PWSTR>(reinterpret_cast<BYTE*>(eventInfo.get()) + eventInfo->EventNameOffset)) == 0)
+ {
+ m_dCreateFilesCalled++;
+ }
+ }
+ return S_OK;
+ }();
+ }
+};
+
+// {6e7b1892-5288-5fe5-8f34-e3b0dc671fd2}
+static const GUID AudioSesTelemetryProvider =
+{ 0x6e7b1892, 0x5288, 0x5fe5, 0x8f, 0x34, 0xe3, 0xb0, 0xdc, 0x67, 0x1f, 0xd2 };
+
+void CAPOLoggingFrameworkTest::LoggingFrameworkTest()
+{
+ WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
+
+ if (m_dwPlatform != DEVICEFAMILYINFOENUM_WINDOWS_CORE && m_capxEndpoints.size() == 0)
+ {
+ Log::Result(TestResults::Skipped, L"There are no CAPX APOs to test");
+ return;
+ }
+
+ CEtwListener listener;
+ CEventParser parser;
+
+ VERIFY_SUCCEEDED(listener.StartTraceSession(L"LoggingFrameworkTest", static_cast<IEtwEventHandler *>(&parser)));
+
+ // Enable Microsoft.Windows.Audio.Client
+ VERIFY_SUCCEEDED(listener.EnableProvider(AudioSesTelemetryProvider, TRACE_LEVEL_INFORMATION, 8));
+
+ auto stopListener = scope_exit([&] {
+ listener.StopTraceSession();
+ });
+
+ wil::com_ptr_nothrow<IMMDeviceEnumerator> spEnumerator;
+ VERIFY_SUCCEEDED(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, IID_PPV_ARGS(&spEnumerator)));
+
+ RunStressTest(FIVE_MIN_IN_SEC, m_capxEndpoints);
+
+ VERIFY_IS_FALSE(parser.WasRTTThreadDetected());
+ VERIFY_IS_TRUE(parser.GetCountOfCreateFiles() == 0);
+ LOG_OUTPUT(L"Number of APO logs collected: %d", parser.GetCountOfAPOLogging());
+} \ No newline at end of file
diff --git a/audio/tests/HLK/ThirdPartyApoTests/CAPXLoggingFrameworkTests.h b/audio/tests/HLK/ThirdPartyApoTests/CAPXLoggingFrameworkTests.h
new file mode 100644
index 00000000..939b7554
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/CAPXLoggingFrameworkTests.h
@@ -0,0 +1,73 @@
+#include <stdafx.h>
+
+
+#include <wil\resultmacros.h>
+#include <wil\com.h>
+#include <audioclient.h>
+#include <audioclientp.h>
+#include <audiosessiontypesp.h>
+#include <mmdeviceapi.h>
+#include <endpointvolume.h>
+#include "etwlistener.h"
+#include <functiondiscoverykeys.h>
+#include <slpublic.h>
+
+#include <DevPKey.h>
+#include <AudioEngineBaseAPOP.h>
+#include "TestMediaType.h"
+#include <audioenginebaseapo.h>
+
+#include <WexTestClass.h>
+
+#include <list>
+#include <memory>
+
+#include "APOStressTest.h"
+#include "CAPXHelper.h"
+
+using namespace std;
+using namespace wil;
+using namespace WEX::Logging;
+using namespace WEX::Common;
+
+#define POLICY_KERNEL_ONECORE_DEVICE_FAMILY_ID L"Kernel-OneCore-DeviceFamilyID"
+
+class CAPOLoggingFrameworkTest
+{
+ CAPOLoggingFrameworkTest(){};
+ ~CAPOLoggingFrameworkTest(){};
+
+ BEGIN_TEST_CLASS(CAPOLoggingFrameworkTest)
+ START_APPVERIFIFER
+ TEST_CLASS_PROPERTY(L"Owner", L"auddev")
+ TEST_CLASS_PROPERTY(L"TestClassification", L"Feature")
+ TEST_CLASS_PROPERTY(L"BinaryUnderTest", L"audiodg.exe")
+ TEST_CLASS_PROPERTY(L"ArtifactUnderTest", L"audioenginebaseapop.h")
+ TEST_CLASS_PROPERTY(L"RunAs", L"Elevated")
+ TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA")
+ TEST_CLASS_PROPERTY(L"Ignore", L"false")
+ TEST_CLASS_PROPERTY(L"EtwLogger:WPRProfileFile", L"Audio-Tests.wprp")
+ TEST_CLASS_PROPERTY(L"EtwLogger:WPRProfile", L"MultimediaCategory.Verbose.File")
+ END_APPVERIFIER
+ END_TEST_CLASS()
+
+public:
+ TEST_METHOD_SETUP(setUpMethod);
+ TEST_METHOD_CLEANUP(tearDownMethod);
+
+protected:
+ BEGIN_TEST_METHOD(LoggingFrameworkTest)
+ COMMON_ONECORE_TEST_PROPERTIES
+ TEST_METHOD_PROPERTY(L"Kits.TestId", L"4FF3BA81-2539-4762-9F7D-40547D1DAD95")
+ TEST_METHOD_PROPERTY(L"Kits.TestId2", L"FEEC362D-673C-40B3-BB01-5063C4B33EA4")
+ TEST_METHOD_PROPERTY(L"Kits.TestName", L"Audio APO CAPX - Test the Logging Framework - LoggingFrameworkTest")
+ TEST_METHOD_PROPERTY(L"Kits.ExpectedRuntime", L"30")
+ TEST_METHOD_PROPERTY(L"Kits.TimeoutInMinutes", L"60")
+ TEST_METHOD_PROPERTY(L"Kits.Description", L"Third Party CAPX APO Test: LoggingFrameworkTest")
+ APO_TEST_PROPERTIES
+ END_TEST_METHOD()
+
+private:
+ DWORD m_dwPlatform = DEVICEFAMILYINFOENUM_UAP;
+ std::vector<wil::com_ptr<IMMDevice>> m_capxEndpoints;
+};
diff --git a/audio/tests/HLK/ThirdPartyApoTests/CAPXNotificationFrameworkTests.cpp b/audio/tests/HLK/ThirdPartyApoTests/CAPXNotificationFrameworkTests.cpp
new file mode 100644
index 00000000..e55f9764
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/CAPXNotificationFrameworkTests.cpp
@@ -0,0 +1,168 @@
+#include "CAPXNotificationFrameworkTests.h"
+
+
+bool CAPONotificationFrameworkTest::setUpMethod()
+{
+ SLGetWindowsInformationDWORD(POLICY_KERNEL_ONECORE_DEVICE_FAMILY_ID, &m_dwPlatform);
+
+ EndpointsWithCapx(m_capxEndpoints);
+
+ return true;
+}
+
+bool CAPONotificationFrameworkTest::tearDownMethod()
+{
+ return true;
+}
+
+using malloca_deleter = wil::function_deleter<decltype(&::_freea), ::_freea>;
+template <typename T>
+using unique_malloca_ptr = wistd::unique_ptr<T, malloca_deleter>;
+
+class CEventParser : public IEtwEventHandler
+{
+public:
+ int GetCountOfAPONotifications() { return m_countOfAudioProcessingNotifications; }
+ bool WereOldNotificationsDetected() { return m_bOldNotificationsDetected; }
+
+private:
+
+ int m_countOfAudioProcessingNotifications = 0;
+ DWORD m_dLastPid = 0;
+ DWORD m_dLastThreadId = 0;
+ bool m_bOldNotificationsDetected = false;
+
+ std::wstring QueryProcessName(const DWORD pid)
+ {
+ wil::unique_handle hProcess(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid));
+ if(NULL == hProcess)
+ {
+ return L"err " + std::to_wstring(GetLastError());
+ }
+ else
+ {
+ WCHAR szProcessName[1024];
+ DWORD cchSize = ARRAYSIZE(szProcessName);
+ if (0 == QueryFullProcessImageNameW(hProcess.get(), 0, szProcessName, &cchSize))
+ {
+ return L"err " + std::to_wstring(GetLastError());
+ }
+
+ PWSTR fileName = szProcessName + cchSize;
+ while (fileName != szProcessName && *fileName != L'\\') fileName--;
+
+ return (*fileName == L'\\') ? fileName + 1 : fileName;
+ }
+ }
+
+ void OnEvent(PEVENT_RECORD pEventRecord)
+ {
+ WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
+ [&]() {
+ ULONG bufferSize = 0;
+ if (TdhGetEventInformation(pEventRecord, 0, nullptr, nullptr, &bufferSize) == ERROR_INSUFFICIENT_BUFFER)
+ {
+ unique_malloca_ptr<TRACE_EVENT_INFO> eventInfo(reinterpret_cast<PTRACE_EVENT_INFO>(_malloca(bufferSize)));
+ VERIFY_IS_NOT_NULL(eventInfo);
+ RETURN_IF_WIN32_ERROR(TdhGetEventInformation(pEventRecord, 0, nullptr, eventInfo.get(), &bufferSize));
+
+ // Check for old notification types
+ if (_wcsicmp(L"IAudioProcessingObjectNotifications implemented", reinterpret_cast<PWSTR>(reinterpret_cast<BYTE *>(eventInfo.get()) + eventInfo->EventNameOffset)) == 0)
+ {
+ m_countOfAudioProcessingNotifications++;
+ m_dLastPid = pEventRecord->EventHeader.ProcessId;
+ m_dLastThreadId = pEventRecord->EventHeader.ThreadId;
+ }
+ if (_wcsicmp(L"OnPropertyValueChanged", reinterpret_cast<PWSTR>(reinterpret_cast<BYTE *>(eventInfo.get()) + eventInfo->EventNameOffset)) == 0)
+ {
+ if (m_dLastPid == pEventRecord->EventHeader.ProcessId &&
+ m_dLastThreadId == pEventRecord->EventHeader.ThreadId)
+ {
+ m_bOldNotificationsDetected = true;
+ }
+ }
+ if (_wcsicmp(L"OnEndpointVolumeChanged", reinterpret_cast<PWSTR>(reinterpret_cast<BYTE *>(eventInfo.get()) + eventInfo->EventNameOffset)) == 0)
+ {
+ if (m_dLastPid == pEventRecord->EventHeader.ProcessId &&
+ m_dLastThreadId == pEventRecord->EventHeader.ThreadId)
+ {
+ m_bOldNotificationsDetected = true;
+ }
+ }
+ if (_wcsicmp(L"RegisterEndpointNotificationCallback", reinterpret_cast<PWSTR>(reinterpret_cast<BYTE *>(eventInfo.get()) + eventInfo->EventNameOffset)) == 0 ||
+ _wcsicmp(L"RegisterEndpointNotificationCallbackWithVirtualEnumerator", reinterpret_cast<PWSTR>(reinterpret_cast<BYTE *>(eventInfo.get()) + eventInfo->EventNameOffset)) == 0)
+ {
+ if (m_dLastPid == pEventRecord->EventHeader.ProcessId &&
+ m_dLastThreadId == pEventRecord->EventHeader.ThreadId)
+ {
+ m_bOldNotificationsDetected = true;
+ }
+ }
+ if (_wcsicmp(L"UnregisterEndpointNotificationCallback", reinterpret_cast<PWSTR>(reinterpret_cast<BYTE *>(eventInfo.get()) + eventInfo->EventNameOffset)) == 0 ||
+ _wcsicmp(L"UnregisterEndpointNotificationCallbackWithVirtualEnumerator", reinterpret_cast<PWSTR>(reinterpret_cast<BYTE *>(eventInfo.get()) + eventInfo->EventNameOffset)) == 0)
+ {
+ if (m_dLastPid == pEventRecord->EventHeader.ProcessId &&
+ m_dLastThreadId == pEventRecord->EventHeader.ThreadId)
+ {
+ m_bOldNotificationsDetected = true;
+ }
+ }
+ }
+ return S_OK;
+ }();
+ }
+};
+
+// {6e7b1892-5288-5fe5-8f34-e3b0dc671fd2}
+static const GUID AudioSesTelemetryProvider =
+{ 0x6e7b1892, 0x5288, 0x5fe5, 0x8f, 0x34, 0xe3, 0xb0, 0xdc, 0x67, 0x1f, 0xd2 };
+
+void CAPONotificationFrameworkTest::NotificationFrameworkTest()
+{
+ WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
+
+ if (m_dwPlatform != DEVICEFAMILYINFOENUM_WINDOWS_CORE && m_capxEndpoints.size() == 0)
+ {
+ Log::Result(TestResults::Skipped, L"There are no CAPX APOs to test");
+ return;
+ }
+
+ CEtwListener listener;
+ CEventParser parser;
+
+ VERIFY_SUCCEEDED(listener.StartTraceSession(L"NotificationFrameworkTest", static_cast<IEtwEventHandler *>(&parser)));
+
+ // Enable Microsoft.Windows.Audio.Client
+ VERIFY_SUCCEEDED(listener.EnableProvider(AudioSesTelemetryProvider, TRACE_LEVEL_INFORMATION, 8));
+
+ auto stopListener = scope_exit([&] {
+ listener.StopTraceSession();
+ });
+
+ {
+ for (UINT i = 0; i < m_capxEndpoints.size(); i++)
+ {
+ wil::com_ptr_nothrow<IMMDevice> pEndpoint = m_capxEndpoints.at(i);
+
+ wil::unique_prop_variant var;
+ wil::com_ptr_nothrow<IPropertyStore> spPropertyStore;
+ VERIFY_SUCCEEDED(pEndpoint->OpenPropertyStore(STGM_READ, &spPropertyStore));
+ VERIFY_SUCCEEDED(spPropertyStore->GetValue(PKEY_Device_FriendlyName, &var));
+ VERIFY_ARE_EQUAL(VT_LPWSTR, var.vt);
+ LOG_OUTPUT(L"Testing endpoint: %s", var.pwszVal);
+
+ wil::com_ptr_nothrow<IAudioEndpointVolume> aev;
+ VERIFY_SUCCEEDED(pEndpoint->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (void **)&aev));
+
+ VERIFY_SUCCEEDED(aev->SetMasterVolumeLevelScalar((0.7f), NULL));
+
+ Sleep(500);
+
+ VERIFY_SUCCEEDED(aev->SetMasterVolumeLevelScalar((1.0f), NULL));
+
+ LOG_OUTPUT(L"Number of APO notifications detected: %d", parser.GetCountOfAPONotifications());
+ }
+
+ VERIFY_IS_FALSE(parser.WereOldNotificationsDetected());
+ }
+} \ No newline at end of file
diff --git a/audio/tests/HLK/ThirdPartyApoTests/CAPXNotificationFrameworkTests.h b/audio/tests/HLK/ThirdPartyApoTests/CAPXNotificationFrameworkTests.h
new file mode 100644
index 00000000..0b7244f2
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/CAPXNotificationFrameworkTests.h
@@ -0,0 +1,84 @@
+#include <stdafx.h>
+#include <memory>
+#include <wil\resultmacros.h>
+#include <wil\com.h>
+#include <audioclient.h>
+#include <audioclientp.h>
+#include <audiosessiontypesp.h>
+#include <mmdeviceapi.h>
+#include "etwlistener.h"
+#include <functiondiscoverykeys.h>
+
+#include <wil\resultmacros.h>
+#include <wil\com.h>
+#include <audioclient.h>
+#include <audioclientp.h>
+#include <audiosessiontypesp.h>
+#include <mmdeviceapi.h>
+#include <endpointvolume.h>
+#include "etwlistener.h"
+#include <functiondiscoverykeys.h>
+#include <slpublic.h>
+
+#include <DevPKey.h>
+#include <AudioEngineBaseAPOP.h>
+#include "TestMediaType.h"
+#include <audioenginebaseapo.h>
+
+#include <WexTestClass.h>
+
+#include <list>
+#include <memory>
+
+#include "CAPXHelper.h"
+
+#include <initguid.h>
+#include <guiddef.h>
+DEFINE_GUID(CLSID_TestCapxAPO, 0xA43110A0,0x4D2B,0x4C5B,0x99,0xB0,0xC6,0xF8,0x62,0x08,0x28,0xB1);
+
+using namespace std;
+using namespace wil;
+using namespace WEX::Logging;
+using namespace WEX::Common;
+
+#define POLICY_KERNEL_ONECORE_DEVICE_FAMILY_ID L"Kernel-OneCore-DeviceFamilyID"
+
+class CAPONotificationFrameworkTest
+{
+ CAPONotificationFrameworkTest(){};
+ ~CAPONotificationFrameworkTest(){};
+
+ BEGIN_TEST_CLASS(CAPONotificationFrameworkTest)
+ START_APPVERIFIFER
+ TEST_CLASS_PROPERTY(L"Owner", L"auddev")
+ TEST_CLASS_PROPERTY(L"TestClassification", L"Feature")
+ TEST_CLASS_PROPERTY(L"BinaryUnderTest", L"audiodg.exe")
+ TEST_CLASS_PROPERTY(L"ArtifactUnderTest", L"audioenginebaseapop.h")
+ TEST_CLASS_PROPERTY(L"RunAs", L"Elevated")
+ TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA")
+ TEST_CLASS_PROPERTY(L"Ignore", L"false")
+ TEST_CLASS_PROPERTY(L"EtwLogger:WPRProfileFile", L"Audio-Tests.wprp")
+ TEST_CLASS_PROPERTY(L"EtwLogger:WPRProfile", L"MultimediaCategory.Verbose.File")
+ END_APPVERIFIER
+ END_TEST_CLASS()
+
+public:
+ TEST_METHOD_SETUP(setUpMethod);
+ TEST_METHOD_CLEANUP(tearDownMethod);
+
+protected:
+ BEGIN_TEST_METHOD(NotificationFrameworkTest)
+ COMMON_ONECORE_TEST_PROPERTIES
+ TEST_METHOD_PROPERTY(L"Kits.TestId", L"30F6BEE7-2AC9-4434-B1AD-642055B2E871")
+ TEST_METHOD_PROPERTY(L"Kits.TestId2", L"C53BE546-1188-4167-B426-E291524BCFD9")
+ TEST_METHOD_PROPERTY(L"Kits.TestName", L"Audio APO CAPX - Test the Notification Framework - NotificationFrameworkTest")
+ TEST_METHOD_PROPERTY(L"Kits.ExpectedRuntime", L"30")
+ TEST_METHOD_PROPERTY(L"Kits.TimeoutInMinutes", L"60")
+ TEST_METHOD_PROPERTY(L"Kits.Description", L"Third Party CAPX APO Test: NotificationFrameworkTest")
+ APO_TEST_PROPERTIES
+ END_TEST_METHOD()
+
+private:
+ DWORD m_dwPlatform = DEVICEFAMILYINFOENUM_UAP;
+ std::vector<wil::com_ptr<IMMDevice>> m_capxEndpoints;
+};
diff --git a/audio/tests/HLK/ThirdPartyApoTests/CAPXThreadingFrameworkTests.cpp b/audio/tests/HLK/ThirdPartyApoTests/CAPXThreadingFrameworkTests.cpp
new file mode 100644
index 00000000..e670518c
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/CAPXThreadingFrameworkTests.cpp
@@ -0,0 +1,118 @@
+#include "CAPXThreadingFrameworkTests.h"
+
+
+bool CAPOThreadingFrameworkTest::setUpMethod()
+{
+ SLGetWindowsInformationDWORD(POLICY_KERNEL_ONECORE_DEVICE_FAMILY_ID, &m_dwPlatform);
+
+ EndpointsWithCapx(m_capxEndpoints);
+
+ return SetupSkipRTHeap();
+}
+
+bool CAPOThreadingFrameworkTest::tearDownMethod()
+{
+ return CleanupSkipRTHeap();
+}
+
+using malloca_deleter = wil::function_deleter<decltype(&::_freea), ::_freea>;
+template <typename T>
+using unique_malloca_ptr = wistd::unique_ptr<T, malloca_deleter>;
+int g_mmThreadCount = 0;
+
+class CEventParser : public IEtwEventHandler
+{
+public:
+ int GetCountOfAPOThreads() { return m_countOfAPOThreads; }
+
+private:
+
+ int m_countOfAPOThreads = 0;
+
+ std::wstring QueryProcessName(const DWORD pid)
+ {
+ wil::unique_handle hProcess(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid));
+ if(NULL == hProcess)
+ {
+ return L"err " + std::to_wstring(GetLastError());
+ }
+ else
+ {
+ WCHAR szProcessName[1024];
+ DWORD cchSize = ARRAYSIZE(szProcessName);
+ if (0 == QueryFullProcessImageNameW(hProcess.get(), 0, szProcessName, &cchSize))
+ {
+ return L"err " + std::to_wstring(GetLastError());
+ }
+
+ PWSTR fileName = szProcessName + cchSize;
+ while (fileName != szProcessName && *fileName != L'\\') fileName--;
+
+ return (*fileName == L'\\') ? fileName + 1 : fileName;
+ }
+ }
+
+ void OnEvent(PEVENT_RECORD pEventRecord)
+ {
+ WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
+ [&]() {
+ ULONG bufferSize = 0;
+ if (TdhGetEventInformation(pEventRecord, 0, nullptr, nullptr, &bufferSize) == ERROR_INSUFFICIENT_BUFFER)
+ {
+ unique_malloca_ptr<TRACE_EVENT_INFO> eventInfo(reinterpret_cast<PTRACE_EVENT_INFO>(_malloca(bufferSize)));
+ VERIFY_IS_NOT_NULL(eventInfo);
+ RETURN_IF_WIN32_ERROR(TdhGetEventInformation(pEventRecord, 0, nullptr, eventInfo.get(), &bufferSize));
+
+ // Threading implemented is the temporary name that the threading framework will be called until the final logs are created
+ if (_wcsicmp(L"Threading implemented", reinterpret_cast<PWSTR>(reinterpret_cast<BYTE*>(eventInfo.get()) + eventInfo->EventNameOffset)) == 0)
+ {
+ m_countOfAPOThreads++;
+ }
+ auto mmThreadMock = Mock10::Mock::Function(&AvSetMmThreadCharacteristics, [](LPCWSTR taskName, LPDWORD taskIndex) {
+ g_mmThreadCount++;
+ return AvSetMmThreadCharacteristics(taskName, taskIndex);
+ });
+ if (_wcsicmp(L"CreateThread", reinterpret_cast<PWSTR>(reinterpret_cast<BYTE*>(eventInfo.get()) + eventInfo->EventNameOffset)) == 0)
+ {
+ g_mmThreadCount++;
+ }
+ }
+ return S_OK;
+ }();
+ }
+};
+
+// {6e7b1892-5288-5fe5-8f34-e3b0dc671fd2}
+static const GUID AudioSesTelemetryProvider =
+{ 0x6e7b1892, 0x5288, 0x5fe5, 0x8f, 0x34, 0xe3, 0xb0, 0xdc, 0x67, 0x1f, 0xd2 };
+
+void CAPOThreadingFrameworkTest::ThreadingFrameworkTest()
+{
+ WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
+
+ if (m_dwPlatform != DEVICEFAMILYINFOENUM_WINDOWS_CORE && m_capxEndpoints.size() == 0)
+ {
+ Log::Result(TestResults::Skipped, L"There are no CAPX APOs to test");
+ return;
+ }
+
+ CEtwListener listener;
+ CEventParser parser;
+
+ VERIFY_SUCCEEDED(listener.StartTraceSession(L"ThreadingFrameworkTest", static_cast<IEtwEventHandler *>(&parser)));
+
+ // Enable Microsoft.Windows.Audio.Client
+ VERIFY_SUCCEEDED(listener.EnableProvider(AudioSesTelemetryProvider, TRACE_LEVEL_INFORMATION, 8));
+
+ auto stopListener = scope_exit([&] {
+ listener.StopTraceSession();
+ });
+
+ wil::com_ptr_nothrow<IMMDeviceEnumerator> spEnumerator;
+ VERIFY_SUCCEEDED(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, IID_PPV_ARGS(&spEnumerator)));
+
+ RunStressTest(FIVE_MIN_IN_SEC, m_capxEndpoints);
+
+ LOG_OUTPUT(L"Number of APO threads created: %d", parser.GetCountOfAPOThreads());
+ VERIFY_IS_TRUE(g_mmThreadCount == 0);
+} \ No newline at end of file
diff --git a/audio/tests/HLK/ThirdPartyApoTests/CAPXThreadingFrameworkTests.h b/audio/tests/HLK/ThirdPartyApoTests/CAPXThreadingFrameworkTests.h
new file mode 100644
index 00000000..47b63766
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/CAPXThreadingFrameworkTests.h
@@ -0,0 +1,73 @@
+#include <stdafx.h>
+
+#include <avrt.h>
+#include <wil\resultmacros.h>
+#include <wil\com.h>
+#include <audioclient.h>
+#include <audioclientp.h>
+#include <audiosessiontypesp.h>
+#include <mmdeviceapi.h>
+#include <endpointvolume.h>
+#include "etwlistener.h"
+#include <functiondiscoverykeys.h>
+#include <slpublic.h>
+
+#include <DevPKey.h>
+#include <AudioEngineBaseAPOP.h>
+#include "TestMediaType.h"
+#include <audioenginebaseapo.h>
+
+#include <WexTestClass.h>
+
+#include <list>
+#include <memory>
+
+#include "APOStressTest.h"
+#include "CAPXHelper.h"
+
+using namespace std;
+using namespace wil;
+using namespace WEX::Logging;
+using namespace WEX::Common;
+
+#define POLICY_KERNEL_ONECORE_DEVICE_FAMILY_ID L"Kernel-OneCore-DeviceFamilyID"
+
+class CAPOThreadingFrameworkTest
+{
+ CAPOThreadingFrameworkTest(){};
+ ~CAPOThreadingFrameworkTest(){};
+
+ BEGIN_TEST_CLASS(CAPOThreadingFrameworkTest)
+ START_APPVERIFIFER
+ TEST_CLASS_PROPERTY(L"Owner", L"auddev")
+ TEST_CLASS_PROPERTY(L"TestClassification", L"Feature")
+ TEST_CLASS_PROPERTY(L"BinaryUnderTest", L"audiodg.exe")
+ TEST_CLASS_PROPERTY(L"ArtifactUnderTest", L"audioenginebaseapop.h")
+ TEST_CLASS_PROPERTY(L"RunAs", L"Elevated")
+ TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA")
+ TEST_CLASS_PROPERTY(L"Ignore", L"false")
+ TEST_CLASS_PROPERTY(L"EtwLogger:WPRProfileFile", L"Audio-Tests.wprp")
+ TEST_CLASS_PROPERTY(L"EtwLogger:WPRProfile", L"MultimediaCategory.Verbose.File")
+ END_APPVERIFIER
+ END_TEST_CLASS()
+
+public:
+ TEST_METHOD_SETUP(setUpMethod);
+ TEST_METHOD_CLEANUP(tearDownMethod);
+
+protected:
+ BEGIN_TEST_METHOD(ThreadingFrameworkTest)
+ COMMON_ONECORE_TEST_PROPERTIES
+ TEST_METHOD_PROPERTY(L"Kits.TestId", L"392B0972-F7EA-42A7-BA24-6304C3C621DB")
+ TEST_METHOD_PROPERTY(L"Kits.TestId2", L"5A5448AF-9D13-44B2-BC0C-D352A9B37268")
+ TEST_METHOD_PROPERTY(L"Kits.TestName", L"Audio APO CAPX - Test the Threading Framework - ThreadingFrameworkTest")
+ TEST_METHOD_PROPERTY(L"Kits.ExpectedRuntime", L"30")
+ TEST_METHOD_PROPERTY(L"Kits.TimeoutInMinutes", L"60")
+ TEST_METHOD_PROPERTY(L"Kits.Description", L"Third Party CAPX APO Test: ThreadingFrameworkTest")
+ APO_TEST_PROPERTIES
+ END_TEST_METHOD()
+
+private:
+ DWORD m_dwPlatform = DEVICEFAMILYINFOENUM_UAP;
+ std::vector<wil::com_ptr<IMMDevice>> m_capxEndpoints;
+};
diff --git a/audio/tests/HLK/ThirdPartyApoTests/FormatHelpers.h b/audio/tests/HLK/ThirdPartyApoTests/FormatHelpers.h
new file mode 100644
index 00000000..781b9ffb
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/FormatHelpers.h
@@ -0,0 +1,330 @@
+//
+// FormatHelpers.h -- Copyright (c) Microsoft Corporation
+//
+// Author: zaneh
+//
+// Description:
+//
+// Format Helpers for test formats used in APODeviceTest
+//
+#pragma once
+
+#include <MMDeviceAPIp.h>
+#include <DeviceTopologyp.h>
+#include <mfapi.h>
+#include <AVEndpointKeys.h>
+#include <AudioCoreAPO32Params.h>
+#include <ksmedia.h>
+
+// Consts used for APO format creation
+static const int cFrameRate = 48000; // 48kHz
+static const int cProcessingPeriod = 10; // milliseconds
+static const int cMaxFrameCount = cFrameRate * cProcessingPeriod / 1000;
+static const int cFrameCountToProcess = cMaxFrameCount / 2;
+
+// Returns true if the two IAudioMediaType formats are equal.
+// False otherwise
+bool IsEqualFormat
+(
+ IAudioMediaType *pIAMTFormat1,
+ IAudioMediaType *pIAMTFormat2
+)
+{
+ UINT cbBuffer1, cbBuffer2;
+ WAVEFORMATEX const *pwfx1, *pwfx2;
+ UNCOMPRESSEDAUDIOFORMAT format1, format2;
+
+ pwfx1 = pIAMTFormat1->GetAudioFormat();
+ pwfx2 = pIAMTFormat2->GetAudioFormat();
+ cbBuffer1 = ((WAVE_FORMAT_PCM == pwfx1->wFormatTag)?sizeof(PCMWAVEFORMAT):(sizeof(WAVEFORMATEX) + pwfx1->cbSize));
+ cbBuffer2 = ((WAVE_FORMAT_PCM == pwfx2->wFormatTag)?sizeof(PCMWAVEFORMAT):(sizeof(WAVEFORMATEX) + pwfx2->cbSize));
+
+ if (cbBuffer1 != cbBuffer2)
+ {
+ return false;
+ }
+
+ // Two formats don't compare as WAVEFORMATEX...
+ if (0 != memcmp(pwfx1, pwfx2, cbBuffer1))
+ {
+ return false;
+ }
+
+ SecureZeroMemory(&format1, sizeof(format1));
+ SecureZeroMemory(&format2, sizeof(format2));
+
+ if (S_OK != pIAMTFormat1->GetUncompressedAudioFormat(&format1))
+ {
+ return false;
+ }
+
+ if (S_OK != pIAMTFormat2->GetUncompressedAudioFormat(&format2))
+ {
+ return false;
+ }
+
+ // Two formats don't compare as WAVEFORMATEX...
+ if (0 != memcmp(&format1, &format2, sizeof(UNCOMPRESSEDAUDIOFORMAT)))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Creates a KSData format from the given WaveFormatEx
+// Returns a struct containing both the KSData format and WaveFormatEx
+KSDATAFORMAT_WAVEFORMATEX *CreateKSDataFromWFX
+(
+ WAVEFORMATEX *pwfx
+)
+{
+ if (nullptr == pwfx)
+ {
+ return nullptr;
+ }
+
+ UINT cbAlloc;
+ cbAlloc = sizeof(KSDATAFORMAT_WAVEFORMATEX) + pwfx->cbSize;
+
+ wil::unique_cotaskmem_ptr<KSDATAFORMAT_WAVEFORMATEX> pKsFormat((KSDATAFORMAT_WAVEFORMATEX*)(CoTaskMemAlloc(cbAlloc)));
+
+ if (nullptr == pKsFormat)
+ {
+ return nullptr;
+ }
+
+ pKsFormat->DataFormat.FormatSize = cbAlloc;
+ pKsFormat->DataFormat.Flags = 0;
+ pKsFormat->DataFormat.Reserved = 0;
+ pKsFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
+ pKsFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
+
+ CopyMemory(&(pKsFormat->WaveFormatEx), pwfx, sizeof(WAVEFORMATEX) + pwfx->cbSize);
+
+ if (WAVE_FORMAT_EXTENSIBLE == pwfx->wFormatTag)
+ {
+ pKsFormat->DataFormat.SubFormat = ((WAVEFORMATEXTENSIBLE*)(pwfx))->SubFormat;
+ }
+ else
+ {
+ INIT_WAVEFORMATEX_GUID(&(pKsFormat->DataFormat.SubFormat), pwfx->wFormatTag);
+ }
+
+ return (pKsFormat.release());
+}
+
+// Creates an IAudioMediaType given an uncompressed audio format
+HRESULT AECreateAudioMediaTypeFromUncompressedAudioFormat(const UNCOMPRESSEDAUDIOFORMAT* pUncompressedAudioFormat,IAudioMediaType** ppIAudioMediaType)
+{
+ RETURN_IF_FAILED(CTestAudioMediaType::Create(pUncompressedAudioFormat, ppIAudioMediaType));
+
+ return S_OK;
+}
+
+// Creates an IAudioMediaType given a WaveFormatEx
+HRESULT AECreateAudioMediaType(const WAVEFORMATEX* pWfx, IAudioMediaType** ppIAudioMediaType)
+{
+ UNCOMPRESSEDAUDIOFORMAT audioFormat;
+
+ audioFormat.dwBytesPerSampleContainer = pWfx->nBlockAlign / pWfx->nChannels;
+ audioFormat.dwSamplesPerFrame = pWfx->nChannels;
+ if (WAVE_FORMAT_EXTENSIBLE == pWfx->wFormatTag)
+ {
+ audioFormat.dwValidBitsPerSample = ((WAVEFORMATEXTENSIBLE*)pWfx)->Samples.wValidBitsPerSample;
+ audioFormat.fFramesPerSecond = (float)(((WAVEFORMATEXTENSIBLE*)pWfx)->Format.nSamplesPerSec);
+ audioFormat.guidFormatType = ((WAVEFORMATEXTENSIBLE*)pWfx)->SubFormat;
+ }
+ else
+ {
+ audioFormat.dwValidBitsPerSample = pWfx->wBitsPerSample;
+ audioFormat.fFramesPerSecond = (float)(pWfx->nSamplesPerSec);
+ INIT_WAVEFORMATEX_GUID(&(audioFormat.guidFormatType), pWfx->wFormatTag);
+ }
+
+ RETURN_IF_FAILED(CTestAudioMediaType::Create(&audioFormat, ppIAudioMediaType));
+ return S_OK;
+}
+
+// Fills an APO connection using the provided uncompressed format.
+// If pBuffer is NULL, the connection will be created with an APO_CONNECTION_BUFFER_TYPE_ALLOCATED.
+// If pBuffer is not null, APO_CONNECTION_BUFFER_TYPE_EXTERNAL will be used.
+// Outptr pConnection returns an APO_CONNECTION_DESCRIPTOR
+HRESULT FillConnection
+(
+ UNCOMPRESSEDAUDIOFORMAT* Format,
+ UINT_PTR pBuffer,
+ UINT32 /* u32ExtraFrameCount */,
+ UINT32 u32MaxFrameCount,
+ APO_CONNECTION_DESCRIPTOR* pConnection
+)
+{
+ if (Format == nullptr)
+ {
+ LOG_ERROR(L"FillConnection recieved null format");
+ return E_INVALIDARG;
+ }
+ if (pConnection == nullptr)
+ {
+ LOG_ERROR(L"FillConnection recieved null APO connection descriptor");
+ return E_INVALIDARG;
+ }
+
+ IAudioMediaType *pFormat;
+
+ // Attempt to create the AudioMediaType using the standard API
+ HRESULT createFormatHr = CreateAudioMediaTypeFromUncompressedAudioFormat(
+ Format,
+ &pFormat);
+
+ if (FAILED(createFormatHr))
+ {
+ LOG_OUTPUT(L"Standard AudioMediaType creation failed. Attempting creation using TestMediaType");
+ RETURN_IF_FAILED(AECreateAudioMediaTypeFromUncompressedAudioFormat(Format, &pFormat));
+ }
+
+ // set connection type based on pBuffer
+ // this will get re(set) when the actual allocation occurs
+ if (NULL != pBuffer)
+ {
+ pConnection->Type = APO_CONNECTION_BUFFER_TYPE_EXTERNAL;
+ }
+ else
+ {
+ pConnection->Type = APO_CONNECTION_BUFFER_TYPE_ALLOCATED;
+ }
+
+ pConnection->pFormat = pFormat;
+ pConnection->pBuffer = pBuffer;
+ pConnection->u32MaxFrameCount = u32MaxFrameCount;
+ pConnection->u32Signature = APO_CONNECTION_DESCRIPTOR_SIGNATURE;
+
+ return createFormatHr;
+}
+
+// Creates a WaveFormatEx format
+void FillFormat
+(
+ WORD FormatType,
+ DWORD dwSamplesPerFrame,
+ DWORD /* dwBytesPerSampleContainer */,
+ DWORD dwValidBitsPerSample,
+ FLOAT32 fFramesPerSecond,
+ WAVEFORMATEX* pWfx
+)
+{
+ if (pWfx == nullptr)
+ {
+ LOG_ERROR(L"WaveformatEx is null");
+ }
+
+ if (dwSamplesPerFrame >= 0xffff)
+ {
+ LOG_ERROR(L"SamplesPerFrame too great");
+ }
+
+ if (dwValidBitsPerSample >= 0xffff)
+ {
+ LOG_ERROR(L"ValidBitsPerSample too great");
+ }
+
+ pWfx->wFormatTag = FormatType;
+ pWfx->nChannels = (WORD)(dwSamplesPerFrame & 0xffff);
+ pWfx->wBitsPerSample = (WORD)dwValidBitsPerSample;
+ pWfx->nBlockAlign = pWfx->nChannels * (pWfx->wBitsPerSample / 8);
+ pWfx->nSamplesPerSec = (DWORD)fFramesPerSecond;
+ pWfx->nAvgBytesPerSec = pWfx->nSamplesPerSec * pWfx->nBlockAlign;
+ pWfx->cbSize = 0;
+}
+
+// Creates an UncompressedAudioFormat
+void FillFormat
+(
+ GUID FormatType,
+ DWORD dwSamplesPerFrame,
+ DWORD dwBytesPerSampleContainer,
+ DWORD dwValidBitsPerSample,
+ FLOAT32 fFramesPerSecond,
+ DWORD dwChannelMask,
+ UNCOMPRESSEDAUDIOFORMAT* pFormat
+)
+{
+ if (pFormat == nullptr)
+ {
+ LOG_ERROR(L"WaveformatEx is null");
+ }
+
+ if (dwSamplesPerFrame >= 0xffff)
+ {
+ LOG_ERROR(L"SamplesPerFrame too great");
+ }
+
+ if (dwValidBitsPerSample >= 0xffff)
+ {
+ LOG_ERROR(L"ValidBitsPerSample too great");
+ }
+
+ pFormat->guidFormatType = FormatType;
+ pFormat->dwSamplesPerFrame = dwSamplesPerFrame;
+ pFormat->dwBytesPerSampleContainer = dwBytesPerSampleContainer;
+ pFormat->dwValidBitsPerSample = dwValidBitsPerSample;
+ pFormat->fFramesPerSecond = fFramesPerSecond;
+ pFormat->dwChannelMask = dwChannelMask;
+}
+
+HRESULT SetupConnection
+(
+ APO_CONNECTION_DESCRIPTOR* pInputConnDesc,
+ APO_CONNECTION_DESCRIPTOR* pOutputConnDesc,
+ APO_CONNECTION_PROPERTY* pInputConnProp,
+ APO_CONNECTION_PROPERTY* pOutputConnProp,
+ UNCOMPRESSEDAUDIOFORMAT* pDefaultFormat
+)
+{
+ if (pInputConnDesc == nullptr)
+ {
+ LOG_ERROR(L"SetupConnection recieved null APO connection descriptor for input");
+ return E_INVALIDARG;
+ }
+
+ if (pOutputConnDesc == nullptr)
+ {
+ LOG_ERROR(L"SetupConnection recieved null APO connection descriptor for output");
+ return E_INVALIDARG;
+ }
+
+ if (pInputConnProp == nullptr)
+ {
+ LOG_ERROR(L"SetupConnection recieved null APO connection property for input");
+ return E_INVALIDARG;
+ }
+
+ if (pOutputConnProp == nullptr)
+ {
+ LOG_ERROR(L"SetupConnection recieved null APO connection property for output");
+ return E_INVALIDARG;
+ }
+
+ if (pDefaultFormat == nullptr)
+ {
+ LOG_ERROR(L"SetupConnection received null format");
+ return E_INVALIDARG;
+ }
+
+ LOG_RETURN_IF_FAILED(FillConnection(pDefaultFormat, NULL, 0, cMaxFrameCount, pInputConnDesc),
+ L"\tFillConnection for input descriptor failed");
+
+ LOG_RETURN_IF_FAILED(CreateConnection(pInputConnDesc, pInputConnProp),
+ L"\tCreateConnection for input descriptor failed");
+
+ pInputConnProp->u32ValidFrameCount = cFrameCountToProcess;
+ pInputConnProp->u32BufferFlags = BUFFER_VALID;
+
+ LOG_RETURN_IF_FAILED(FillConnection(pDefaultFormat, NULL, 0, cMaxFrameCount, pOutputConnDesc),
+ L"\tFillConnection for output descriptor failed");
+
+ LOG_RETURN_IF_FAILED(CreateConnection(pOutputConnDesc, pOutputConnProp),
+ L"\tCreateConnection for output descriptor failed");
+
+ return S_OK;
+} \ No newline at end of file
diff --git a/audio/tests/HLK/ThirdPartyApoTests/TestEffectsList.cpp b/audio/tests/HLK/ThirdPartyApoTests/TestEffectsList.cpp
new file mode 100644
index 00000000..7b670d28
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/TestEffectsList.cpp
@@ -0,0 +1,225 @@
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+
+#include <stdafx.h>
+#include <memory>
+#include <wil\resultmacros.h>
+#include <wil\com.h>
+#include <wil\winrt.h>
+#include <wil\wrl.h>
+#include <audioclient.h>
+#include <mmdeviceapi.h>
+#include <functiondiscoverykeys.h>
+#include <windows.media.effects.h>
+#include "avdevqueryhelpers.h"
+#include <AudioStreamCategoryConversions.h>
+
+using namespace Windows::Media::Effects;
+
+class CTestEffectsList
+{
+ BEGIN_TEST_CLASS(CTestEffectsList)
+ START_APPVERIFIFER
+ TEST_CLASS_PROPERTY(L"Owner", L"auddev")
+ TEST_CLASS_PROPERTY(L"TestClassification", L"Feature")
+ TEST_CLASS_PROPERTY(L"BinaryUnderTest", L"audiodg.exe")
+ TEST_CLASS_PROPERTY(L"ArtifactUnderTest", L"audioengineextensionapo.h")
+ TEST_CLASS_PROPERTY(L"RunAs", L"Elevated")
+ TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA")
+ TEST_CLASS_PROPERTY(L"Ignore", L"false")
+ TEST_CLASS_PROPERTY(L"EtwLogger:WPRProfileFile", L"Audio-Tests.wprp")
+ TEST_CLASS_PROPERTY(L"EtwLogger:WPRProfile", L"MultimediaCategory.Verbose.File")
+ END_APPVERIFIER
+ END_TEST_CLASS()
+
+protected:
+ BEGIN_TEST_METHOD(TestGetEffectsList)
+ COMMON_ONECORE_TEST_PROPERTIES
+ TEST_METHOD_PROPERTY(L"Kits.TestId", L"7E8037CA-8670-4170-8EC8-C7B02B22A7B4")
+ TEST_METHOD_PROPERTY(L"Kits.TestId2", L"FD1ED3C6-54E0-432B-B3C9-5EAC5DE2D3E1")
+ TEST_METHOD_PROPERTY(L"Kits.TestName", L"Audio APO - Test IAudioSystemEffects2 and IAudioSystemEffects3 usage from APOs - TestEffectsList")
+ TEST_METHOD_PROPERTY(L"Kits.ExpectedRuntime", L"30")
+ TEST_METHOD_PROPERTY(L"Kits.TimeoutInMinutes", L"60")
+ TEST_METHOD_PROPERTY(L"Kits.Description", L"Third Party APO Test: TestEffectsList")
+ APO_TEST_PROPERTIES
+ END_TEST_METHOD()
+};
+
+GUID AudioEffectTypeToGUID(Windows::Media::Effects::AudioEffectType type)
+{
+ switch(type)
+ {
+ case AudioEffectType_AcousticEchoCancellation:
+ return AUDIO_EFFECT_TYPE_ACOUSTIC_ECHO_CANCELLATION;
+ case AudioEffectType_NoiseSuppression:
+ return AUDIO_EFFECT_TYPE_NOISE_SUPPRESSION;
+ case AudioEffectType_AutomaticGainControl:
+ return AUDIO_EFFECT_TYPE_AUTOMATIC_GAIN_CONTROL;
+ case AudioEffectType_BeamForming:
+ return AUDIO_EFFECT_TYPE_BEAMFORMING;
+ case AudioEffectType_ConstantToneRemoval:
+ return AUDIO_EFFECT_TYPE_CONSTANT_TONE_REMOVAL;
+ case AudioEffectType_Equalizer:
+ return AUDIO_EFFECT_TYPE_EQUALIZER;
+ case AudioEffectType_LoudnessEqualizer:
+ return AUDIO_EFFECT_TYPE_LOUDNESS_EQUALIZER;
+ case AudioEffectType_BassBoost:
+ return AUDIO_EFFECT_TYPE_BASS_BOOST;
+ case AudioEffectType_VirtualSurround:
+ return AUDIO_EFFECT_TYPE_VIRTUAL_SURROUND;
+ case AudioEffectType_VirtualHeadphones:
+ return AUDIO_EFFECT_TYPE_VIRTUAL_HEADPHONES;
+ case AudioEffectType_SpeakerFill:
+ return AUDIO_EFFECT_TYPE_SPEAKER_FILL;
+ case AudioEffectType_RoomCorrection:
+ return AUDIO_EFFECT_TYPE_ROOM_CORRECTION;
+ case AudioEffectType_BassManagement:
+ return AUDIO_EFFECT_TYPE_BASS_MANAGEMENT;
+ case AudioEffectType_EnvironmentalEffects:
+ return AUDIO_EFFECT_TYPE_ENVIRONMENTAL_EFFECTS;
+ case AudioEffectType_SpeakerProtection:
+ return AUDIO_EFFECT_TYPE_SPEAKER_PROTECTION;
+ case AudioEffectType_SpeakerCompensation:
+ return AUDIO_EFFECT_TYPE_SPEAKER_COMPENSATION;
+ case AudioEffectType_DynamicRangeCompression:
+ return AUDIO_EFFECT_TYPE_DYNAMIC_RANGE_COMPRESSION;
+ case AudioEffectType_FarFieldBeamForming:
+ return AUDIO_EFFECT_TYPE_FAR_FIELD_BEAMFORMING;
+ case AudioEffectType_DeepNoiseSuppression:
+ return AUDIO_EFFECT_TYPE_DEEP_NOISE_SUPPRESSION;
+ }
+ return GUID_NULL;
+}
+
+void CTestEffectsList::TestGetEffectsList()
+{
+ WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
+
+ wil::com_ptr_nothrow<IMMDeviceEnumerator> spEnumerator;
+ VERIFY_SUCCEEDED(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, IID_PPV_ARGS(&spEnumerator)));
+
+ EDataFlow dataFlows[] = { eRender, eCapture };
+
+ for (EDataFlow dataFlow : dataFlows)
+ {
+ wil::com_ptr_nothrow<IMMDeviceCollection> spDevices;
+ VERIFY_SUCCEEDED(spEnumerator->EnumAudioEndpoints(dataFlow, DEVICE_STATE_ACTIVE, &spDevices));
+
+ UINT cDevices = 0;
+ VERIFY_SUCCEEDED(spDevices->GetCount(&cDevices));
+
+ for (UINT i = 0; i < cDevices; i++)
+ {
+ wil::com_ptr_nothrow<IMMDevice> spEndpoint;
+ VERIFY_SUCCEEDED(spDevices->Item(i, &spEndpoint));
+
+ wil::unique_prop_variant var;
+ wil::com_ptr_nothrow<IPropertyStore> spPropertyStore;
+ VERIFY_SUCCEEDED(spEndpoint->OpenPropertyStore(STGM_READ, &spPropertyStore));
+ VERIFY_SUCCEEDED(spPropertyStore->GetValue(PKEY_Device_FriendlyName, &var));
+ VERIFY_ARE_EQUAL(VT_LPWSTR, var.vt);
+ LOG_OUTPUT(L"Testing endpoint: %s", var.pwszVal);
+
+ wil::unique_cotaskmem_string spDeviceId;
+ VERIFY_SUCCEEDED(spEndpoint->GetId(&spDeviceId));
+ wil::unique_cotaskmem_string spEndpointPnpInstanceId;
+ VERIFY_SUCCEEDED(mmdDevGetInterfaceIdFromMMDeviceId(spDeviceId.get(), &spEndpointPnpInstanceId));
+ HSTRING deviceId;
+ VERIFY_SUCCEEDED(WindowsCreateString(spEndpointPnpInstanceId.get(), (UINT32)wcslen(spEndpointPnpInstanceId.get()), &deviceId));
+
+ // Get effects list using IAudioSystemEffects2
+ wil::com_ptr_nothrow<IAudioEffectsManagerStatics> audioEffectsManagerStatics =
+ wil::GetActivationFactory<IAudioEffectsManagerStatics>(RuntimeClass_Windows_Media_Effects_AudioEffectsManager);
+
+ wil::com_ptr_nothrow<Windows::Foundation::Collections::IVectorView<AudioEffect*>> effects;
+ AUDIO_STREAM_CATEGORY audioCategory;
+
+ if (dataFlow == eRender)
+ {
+ wil::com_ptr_nothrow<IAudioRenderEffectsManager> audioRenderEffectsManager;
+ VERIFY_SUCCEEDED(audioEffectsManagerStatics->CreateAudioRenderEffectsManager(deviceId, Windows::Media::Render::AudioRenderCategory::AudioRenderCategory_Communications, &audioRenderEffectsManager));
+ VERIFY_IS_NOT_NULL(audioRenderEffectsManager);
+ VERIFY_SUCCEEDED(audioRenderEffectsManager->GetAudioRenderEffects(&effects));
+
+ VERIFY_SUCCEEDED(MediaRenderCategory_To_AUDIO_STREAM_CATEGORY(Windows::Media::Render::AudioRenderCategory::AudioRenderCategory_Communications, &audioCategory));
+ }
+ else
+ {
+ wil::com_ptr_nothrow<IAudioCaptureEffectsManager> audioCaptureEffectsManager;
+ VERIFY_SUCCEEDED(audioEffectsManagerStatics->CreateAudioCaptureEffectsManager(deviceId, Windows::Media::Capture::MediaCategory::MediaCategory_Communications, &audioCaptureEffectsManager));
+ VERIFY_IS_NOT_NULL(audioCaptureEffectsManager);
+ VERIFY_SUCCEEDED(audioCaptureEffectsManager->GetAudioCaptureEffects(&effects));
+
+ VERIFY_SUCCEEDED(MediaCaptureCategory_To_AUDIO_STREAM_CATEGORY(Windows::Media::Capture::MediaCategory::MediaCategory_Communications, &audioCategory));
+ }
+
+ UINT32 numEffects = 0;
+ effects->get_Size(&numEffects);
+
+ // Get effects lists using IAudioSystemEffects3
+ wil::com_ptr_nothrow<IAudioClient2> spAudioClient;
+ VERIFY_SUCCEEDED(spEndpoint->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, nullptr, reinterpret_cast<void**>(&spAudioClient)));
+
+ AudioClientProperties clientProperties = {};
+ clientProperties.cbSize = sizeof(AudioClientProperties);
+ clientProperties.bIsOffload = FALSE;
+ clientProperties.eCategory = audioCategory;
+ clientProperties.Options = AUDCLNT_STREAMOPTIONS_NONE;
+ VERIFY_SUCCEEDED(spAudioClient->SetClientProperties(&clientProperties));
+
+ wil::unique_cotaskmem_ptr<WAVEFORMATEX> mixFormat;
+ VERIFY_SUCCEEDED(spAudioClient->GetMixFormat(wil::out_param_ptr<WAVEFORMATEX**>(mixFormat)));
+
+ VERIFY_SUCCEEDED(spAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, 20 * 10000, 0, mixFormat.get(), nullptr));
+
+ wil::com_ptr_nothrow<IAudioEffectsManager> audioEffectsManager;
+ VERIFY_SUCCEEDED(spAudioClient->GetService(IID_PPV_ARGS(&audioEffectsManager)));
+ VERIFY_IS_NOT_NULL(audioEffectsManager);
+
+ wil::unique_cotaskmem_array_ptr<AUDIO_EFFECT> controllableEffects;
+ UINT32 numControllableEffects;
+ VERIFY_SUCCEEDED(audioEffectsManager->GetAudioEffects(&controllableEffects, &numControllableEffects));
+
+ // Verify 'effects' is a subset of 'controllableEffects'
+ VERIFY_IS_GREATER_THAN_OR_EQUAL(numControllableEffects, numEffects);
+ for (UINT32 i = 0; i < numEffects; i++)
+ {
+ bool found = false;
+ for (UINT32 j = 0; j < numControllableEffects && !found; j++)
+ {
+ AudioEffectType effectType;
+ wil::com_ptr_nothrow<IAudioEffect> spEffect;
+ effects->GetAt(i, &spEffect);
+ spEffect->get_AudioEffectType(&effectType);
+ if (IsEqualGUID(AudioEffectTypeToGUID(effectType), controllableEffects[j].id))
+ {
+ found = true;
+ }
+ }
+ VERIFY_IS_TRUE(found);
+ }
+
+ // Verify effects not present in 'effects' are disabled
+ for (UINT32 i = 0; i < numControllableEffects; i++)
+ {
+ bool found = false;
+ for (UINT32 j = 0; j < numEffects && !found; j++)
+ {
+ AudioEffectType effectType;
+ wil::com_ptr_nothrow<IAudioEffect> spEffect;
+ effects->GetAt(j, &spEffect);
+ spEffect->get_AudioEffectType(&effectType);
+ if (IsEqualGUID(controllableEffects[i].id, AudioEffectTypeToGUID(effectType)))
+ {
+ found = true;
+ }
+ }
+ if (!found)
+ {
+ VERIFY_ARE_EQUAL(controllableEffects[i].state, AUDIO_EFFECT_STATE_OFF);
+ }
+ }
+ }
+ }
+}
diff --git a/audio/tests/HLK/ThirdPartyApoTests/TestMediaType.cpp b/audio/tests/HLK/ThirdPartyApoTests/TestMediaType.cpp
new file mode 100644
index 00000000..1627b728
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/TestMediaType.cpp
@@ -0,0 +1,227 @@
+// AudioMediaType.cpp -- Copyright (c) 2003 Microsoft Corporation
+//
+//
+// Description:
+//
+// Implementation of the TestMediaType
+//
+
+#include "TestMediaType.h"
+#include <memory>
+#include <wil\resultmacros.h>
+
+//-----------------------------------------------------------------------------
+// Description:
+//
+// Creates an CTestAudioMediaType object with the given format.
+//
+// Parameters:
+//
+// pFormat - [in] Format for the new AudioMediaType.
+// ppIAudioMediaType - [out] upon success returns the pointer to the
+// new interface.
+//
+// Return values:
+//
+// S_OK Success
+// E_OUTOFMEMORY On memory failure.
+// E_INVALIDARG Null parameter
+//
+// Remarks:
+//
+HRESULT CTestAudioMediaType::Create
+(
+ const UNCOMPRESSEDAUDIOFORMAT* pFormat,
+ IAudioMediaType** ppIAudioMediaType
+)
+{
+ if (!pFormat || !ppIAudioMediaType)
+ {
+ return E_INVALIDARG;
+ }
+
+ HRESULT hResult = S_OK;
+
+ *ppIAudioMediaType = NULL;
+
+ std::unique_ptr<CTestAudioMediaType> pObj(new(std::nothrow) CTestAudioMediaType());
+
+ pObj->m_Format = *pFormat;
+
+ // TODO: iter8 fix this to use WAVEFORMATEXTENSIBLE (commented lines)
+ // after KSCommon lib is fixed
+ if (KSDATAFORMAT_SUBTYPE_PCM == pFormat->guidFormatType)
+ {
+ pObj->m_Wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
+ }
+ else
+ {
+ pObj->m_Wfx.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
+ }
+ pObj->m_Wfx.Format.nChannels = (WORD)pObj->m_Format.dwSamplesPerFrame;
+ pObj->m_Wfx.Format.nSamplesPerSec = (DWORD)pObj->m_Format.fFramesPerSecond;
+ pObj->m_Wfx.Format.nAvgBytesPerSec = (DWORD)(pObj->m_Format.dwBytesPerSampleContainer *
+ pObj->m_Format.fFramesPerSecond * pObj->m_Format.dwSamplesPerFrame);
+ pObj->m_Wfx.Format.nBlockAlign = (WORD)(pObj->m_Format.dwBytesPerSampleContainer * pObj->m_Format.dwSamplesPerFrame);
+ pObj->m_Wfx.Format.wBitsPerSample = (WORD)pObj->m_Format.dwValidBitsPerSample;
+ pObj->m_Wfx.Format.cbSize = 0;
+
+ hResult = pObj->QueryInterface(
+ __uuidof(IAudioMediaType),
+ (LPVOID *) ppIAudioMediaType );
+
+ return( hResult );
+} // Create
+
+//-----------------------------------------------------------------------------
+// Description:
+//
+// Used to addref an interface
+//
+// Results:
+//
+// New reference count
+//
+ULONG STDMETHODCALLTYPE CTestAudioMediaType::AddRef()
+{
+ return (ULONG) InterlockedIncrement( (LONG *) &m_cRef );
+} // AddRef
+
+//-----------------------------------------------------------------------------
+// Description:
+//
+// Used to release an interface
+//
+// Results:
+//
+// New reference count
+//
+ULONG STDMETHODCALLTYPE CTestAudioMediaType::Release()
+{
+ ULONG ulNewRefCount = (ULONG) InterlockedDecrement( (LONG *) &m_cRef );
+
+ //
+ // If our new refcount is zero, then we need to delete ourselves
+ //
+ if( 0 == ulNewRefCount )
+ {
+ delete this;
+ }
+
+ return( ulNewRefCount );
+} // Release
+
+//-----------------------------------------------------------------------------
+// Description:
+//
+// Used to query an interface
+//
+// Parameters:
+//
+// riid - [in] id to look for
+// ppvObject - [out] pointer to object
+//
+// Return Values:
+//
+// S_OK On success.
+// E_POINTER Invalid destination pointer
+// E_NOINTERFACE No interface of that type
+// error Other
+//
+STDMETHODIMP CTestAudioMediaType::QueryInterface(
+ REFIID riid, LPVOID *ppvObject )
+{
+ if (!ppvObject)
+ {
+ return E_POINTER;
+ }
+
+ HRESULT hResult;
+
+ hResult = S_OK;
+ *ppvObject = NULL;
+
+ if( ( riid == __uuidof(IAudioMediaType) ) ||
+ ( riid == __uuidof(IUnknown) ) )
+ {
+ *ppvObject = ( IAudioMediaType *)this;
+ }
+ else
+ {
+ hResult = E_NOINTERFACE;
+ }
+
+ if ( SUCCEEDED( hResult ) )
+ {
+ ((LPUNKNOWN) *ppvObject)->AddRef( );
+ }
+
+ return( hResult );
+} // QueryInterface
+
+//-----------------------------------------------------------------------------
+// Description:
+//
+// Not implemented
+//
+// Parameters:
+//
+// pAudioMediaType - [in] media type
+// pdwFlags - [out] flags
+//
+// Return Values:
+//
+// E_NOTIMPL Not implemented.
+//
+HRESULT STDMETHODCALLTYPE CTestAudioMediaType::IsEqual(
+ IAudioMediaType * /* pAudioMediaType */,
+ DWORD * /* pdwFlags */
+)
+{
+ return E_NOTIMPL;
+} // IsEqual
+
+//-----------------------------------------------------------------------------
+// Description:
+//
+// Returns pointer to internal member variable m_Wfx.
+//
+// Results:
+//
+// Returns pointer to WaveFormatEx representing the format.
+//
+const WAVEFORMATEX *STDMETHODCALLTYPE CTestAudioMediaType::GetAudioFormat( void)
+{
+ return reinterpret_cast<WAVEFORMATEX*>(&m_Wfx);
+} // GetAudioFormat
+
+//-----------------------------------------------------------------------------
+// Description:
+//
+// Copies the uncompressed data to the parameter.
+//
+// Parameters:
+//
+// pUncompressedAudioFormat - [in] format pointer
+//
+// Return Values:
+//
+// S_OK On success
+// E_POINTER Invalid pointer
+//
+HRESULT STDMETHODCALLTYPE CTestAudioMediaType::GetUncompressedAudioFormat(
+ UNCOMPRESSEDAUDIOFORMAT *pUncompressedAudioFormat
+)
+{
+ RETURN_HR_IF(E_FAIL, (KSDATAFORMAT_SUBTYPE_PCM != m_Format.guidFormatType) &&
+ (KSDATAFORMAT_SUBTYPE_IEEE_FLOAT != m_Format.guidFormatType));
+
+ if (!pUncompressedAudioFormat)
+ {
+ return E_POINTER;
+ }
+
+ CopyMemory(pUncompressedAudioFormat, &m_Format, sizeof(UNCOMPRESSEDAUDIOFORMAT));
+
+ return S_OK;
+} // GetUncompressedAudioFormat
diff --git a/audio/tests/HLK/ThirdPartyApoTests/TestMediaType.h b/audio/tests/HLK/ThirdPartyApoTests/TestMediaType.h
new file mode 100644
index 00000000..e213a746
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/TestMediaType.h
@@ -0,0 +1,163 @@
+// Copyright (c) Microsoft Corporation
+//
+// Author: Alper Selcuk
+//
+// Description:
+//
+// Declaration of the AudioMediaType
+// The original code is copied from MF tree.
+//
+// Note that this implementation is only useful for some unit tests that need
+// to pass bogus media types.
+//
+#pragma once
+
+#include <AudioMediaType.h>
+
+//-----------------------------------------------------------------------------
+// Description:
+//
+// Implements a stripped down version of IAudioMediaType.
+
+// Remarks:
+//
+// Most methods are not implemented, because they are not needed by the
+// processor.
+//
+// NOTE: [alper] If this is passed to third party APO's then we may be forced
+// to implement all the methods.
+//
+class CTestAudioMediaType : public IAudioMediaType
+{
+public:
+
+ //--------------------------------------------------------------------------
+ // Description:
+ //
+ // Used during creation
+ //
+ // Parameters:
+ //
+ // pFormat - [in] the format
+ // ppIAudioMediaType - [out] Pointer to the created IAudioMediaType.
+ //
+ // Return Values:
+ //
+ // S_OK On success
+ // error Otherwise
+ //
+ static HRESULT Create( const UNCOMPRESSEDAUDIOFORMAT* pFormat,
+ IAudioMediaType** ppIAudioMediaType);
+
+ // IUnknown methods
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+ STDMETHOD( QueryInterface )( REFIID riid, LPVOID *ppvObject );
+
+ //--------------------------------------------------------------------------
+ // Description:
+ //
+ // Get Major Type
+ //
+ // Parameters:
+ //
+ // pguidMajorType - [out] pointer
+ //
+ // Return Values:
+ //
+ // E_NOTIMPL Not supported
+ //
+ virtual HRESULT STDMETHODCALLTYPE GetMajorType(GUID * /* pguidMajorType */)
+ {
+ return E_NOTIMPL;
+ }
+
+ //--------------------------------------------------------------------------
+ // Description:
+ //
+ // Checks to see if the format is compressed.
+ //
+ // Parameters:
+ //
+ // pfCompressed - [out] On S_OK, this is set TRUE.
+ //
+ // Return Values:
+ //
+ // S_OK On success
+ // E_POINTER Bad pointer
+ //
+ virtual HRESULT STDMETHODCALLTYPE IsCompressedFormat(
+ /* [out] */ BOOL* pfCompressed
+ )
+ {
+ if (NULL == pfCompressed)
+ {
+ return( E_POINTER );
+ }
+
+ *pfCompressed = TRUE;
+
+ return( S_OK );
+ }
+
+ //--------------------------------------------------------------------------
+ // Description:
+ //
+ // Checks to see if the media types are equal.
+ //
+ // Parameters:
+ //
+ // pAudioMediaType - [in] Media type.
+ // pdwFlags - [out] flags
+ //
+ // Return Values:
+ //
+ // S_OK On success
+ // error Otherwise
+ //
+ virtual HRESULT STDMETHODCALLTYPE IsEqual( IAudioMediaType *pAudioMediaType,DWORD *pdwFlags);
+
+ //--------------------------------------------------------------------------
+ // Description:
+ //
+ // Gets the Audio Format.
+ //
+ // Results:
+ //
+ // Returns a WAVEFORMATEX pointer.
+ //
+ virtual const WAVEFORMATEX *STDMETHODCALLTYPE GetAudioFormat( void);
+
+ //--------------------------------------------------------------------------
+ // Description:
+ //
+ // Gets the Uncompressed Audio Format.
+ //
+ // Parameters:
+ //
+ // pUncompressedAudioFormat - [out] gets the format.
+ //
+ // Return Values:
+ //
+ // S_OK On success
+ // error Otherwise
+ //
+ virtual HRESULT STDMETHODCALLTYPE GetUncompressedAudioFormat(
+ UNCOMPRESSEDAUDIOFORMAT* pUncompressedAudioFormat );
+
+protected:
+ CTestAudioMediaType();
+
+protected:
+ LONG m_cRef;
+ UNCOMPRESSEDAUDIOFORMAT m_Format;
+ WAVEFORMATEXTENSIBLE m_Wfx;
+};
+
+//-----------------------------------------------------------------------------
+// Called on creation
+inline CTestAudioMediaType::CTestAudioMediaType()
+{
+ m_cRef = 0;
+} // CTestAudioMediaType
+
diff --git a/audio/tests/HLK/ThirdPartyApoTests/TestWasapiUseFromAudioDg.cpp b/audio/tests/HLK/ThirdPartyApoTests/TestWasapiUseFromAudioDg.cpp
new file mode 100644
index 00000000..3b573f87
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/TestWasapiUseFromAudioDg.cpp
@@ -0,0 +1,244 @@
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+
+#include <stdafx.h>
+#include <memory>
+#include <wil\resultmacros.h>
+#include <wil\com.h>
+#include <audioclient.h>
+#include <audioclientp.h>
+#include <audiosessiontypesp.h>
+#include <mmdeviceapi.h>
+#include "etwlistener.h"
+#include <functiondiscoverykeys.h>
+
+class CTestWasapiUsageFromAudioDg
+{
+ BEGIN_TEST_CLASS(CTestWasapiUsageFromAudioDg)
+ START_APPVERIFIFER
+ TEST_CLASS_PROPERTY(L"Owner", L"auddev")
+ TEST_CLASS_PROPERTY(L"TestClassification", L"Feature")
+ TEST_CLASS_PROPERTY(L"BinaryUnderTest", L"audiodg.exe")
+ TEST_CLASS_PROPERTY(L"ArtifactUnderTest", L"audioenginebaseapop.h")
+ TEST_CLASS_PROPERTY(L"RunAs", L"Elevated")
+ TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA")
+ TEST_CLASS_PROPERTY(L"Ignore", L"false")
+ TEST_CLASS_PROPERTY(L"EtwLogger:WPRProfileFile", L"Audio-Tests.wprp")
+ TEST_CLASS_PROPERTY(L"EtwLogger:WPRProfile", L"MultimediaCategory.Verbose.File")
+ END_APPVERIFIER
+ END_TEST_CLASS()
+
+protected:
+ BEGIN_TEST_METHOD(TestStreamCreation)
+ COMMON_ONECORE_TEST_PROPERTIES
+ TEST_METHOD_PROPERTY(L"Kits.TestId", L"50B80D35-5E61-4D91-B201-5F89D67E4A5A")
+ TEST_METHOD_PROPERTY(L"Kits.TestId2", L"216ADA42-25DC-4504-9032-16D63704FB08")
+ TEST_METHOD_PROPERTY(L"Kits.TestName", L"Audio APO - Test WASAPI usage from APOs - TestStreamCreation")
+ TEST_METHOD_PROPERTY(L"Kits.ExpectedRuntime", L"30")
+ TEST_METHOD_PROPERTY(L"Kits.TimeoutInMinutes", L"60")
+ TEST_METHOD_PROPERTY(L"Kits.Description", L"Third Party APO Test: Test WASAPI usage")
+ APO_TEST_PROPERTIES
+ END_TEST_METHOD()
+};
+
+using malloca_deleter = wil::function_deleter<decltype(&::_freea), ::_freea>;
+template <typename T>
+using unique_malloca_ptr = wistd::unique_ptr<T, malloca_deleter>;
+
+class CEventParser : public IEtwEventHandler
+{
+public:
+ int GetCountOfAudioClientInits() { return m_countOfAudioClientInits; }
+ int GetCountOfAudioClientInitsFromAudioDg() { return m_countOfAudioClientInitsFromAudioDg; }
+
+private:
+
+ int m_countOfAudioClientInits = 0;
+ int m_countOfAudioClientInitsFromAudioDg = 0;
+
+ std::wstring QueryProcessName(const DWORD pid)
+ {
+ wil::unique_handle hProcess(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid));
+ if(NULL == hProcess)
+ {
+ return L"err " + std::to_wstring(GetLastError());
+ }
+ else
+ {
+ WCHAR szProcessName[1024];
+ DWORD cchSize = ARRAYSIZE(szProcessName);
+ if (0 == QueryFullProcessImageNameW(hProcess.get(), 0, szProcessName, &cchSize))
+ {
+ return L"err " + std::to_wstring(GetLastError());
+ }
+
+ PWSTR fileName = szProcessName + cchSize;
+ while (fileName != szProcessName && *fileName != L'\\') fileName--;
+
+ return (*fileName == L'\\') ? fileName + 1 : fileName;
+ }
+ }
+
+ void OnEvent(PEVENT_RECORD pEventRecord)
+ {
+ WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
+ [&]() {
+ ULONG bufferSize = 0;
+ if (TdhGetEventInformation(pEventRecord, 0, nullptr, nullptr, &bufferSize) == ERROR_INSUFFICIENT_BUFFER)
+ {
+ unique_malloca_ptr<TRACE_EVENT_INFO> eventInfo(reinterpret_cast<PTRACE_EVENT_INFO>(_malloca(bufferSize)));
+ VERIFY_IS_NOT_NULL(eventInfo);
+ RETURN_IF_WIN32_ERROR(TdhGetEventInformation(pEventRecord, 0, nullptr, eventInfo.get(), &bufferSize));
+
+ // LOG_OUTPUT(L"Received event: %s", reinterpret_cast<PWSTR>(reinterpret_cast<BYTE*>(eventInfo.get()) + eventInfo->EventNameOffset));
+ if (_wcsicmp(L"AudioClientInitialize", reinterpret_cast<PWSTR>(reinterpret_cast<BYTE*>(eventInfo.get()) + eventInfo->EventNameOffset)) == 0)
+ {
+ m_countOfAudioClientInits++;
+
+ try
+ {
+ // LOG_OUTPUT(L"Process name: %s", QueryProcessName(pEventRecord->EventHeader.ProcessId).c_str());
+ if (0 == _wcsicmp(QueryProcessName(pEventRecord->EventHeader.ProcessId).c_str(), L"audiodg.exe"))
+ {
+ m_countOfAudioClientInitsFromAudioDg++;
+ }
+ }
+ CATCH_LOG()
+ }
+ }
+ return S_OK;
+ }();
+ }
+};
+
+// {6e7b1892-5288-5fe5-8f34-e3b0dc671fd2}
+static const GUID AudioSesTelemetryProvider =
+{ 0x6e7b1892, 0x5288, 0x5fe5, 0x8f, 0x34, 0xe3, 0xb0, 0xdc, 0x67, 0x1f, 0xd2 };
+
+void CTestWasapiUsageFromAudioDg::TestStreamCreation()
+{
+ WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
+
+ CEtwListener listener;
+ CEventParser parser;
+
+ VERIFY_SUCCEEDED(listener.StartTraceSession(L"TestWasapiUsageFromAudioDg", static_cast<IEtwEventHandler *>(&parser)));
+
+ // Enable Microsoft.Windows.Audio.Client
+ VERIFY_SUCCEEDED(listener.EnableProvider(AudioSesTelemetryProvider, TRACE_LEVEL_INFORMATION, 8));
+
+ wil::com_ptr_nothrow<IMMDeviceEnumerator> spEnumerator;
+ VERIFY_SUCCEEDED(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, IID_PPV_ARGS(&spEnumerator)));
+
+ // Test Render endpoints - all stream categories are valid except FarFieldSpeech, UniformSpeech, and VoiceTyping
+ {
+ wil::com_ptr_nothrow<IMMDeviceCollection> spDevices;
+ VERIFY_SUCCEEDED(spEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &spDevices));
+
+ UINT cDevices = 0;
+ VERIFY_SUCCEEDED(spDevices->GetCount(&cDevices));
+
+ for (UINT i = 0; i < cDevices; i++)
+ {
+ wil::com_ptr_nothrow<IMMDevice> pEndpoint;
+ VERIFY_SUCCEEDED(spDevices->Item(i, &pEndpoint));
+
+ wil::unique_prop_variant var;
+ wil::com_ptr_nothrow<IPropertyStore> spPropertyStore;
+ VERIFY_SUCCEEDED(pEndpoint->OpenPropertyStore(STGM_READ, &spPropertyStore));
+ VERIFY_SUCCEEDED(spPropertyStore->GetValue(PKEY_Device_FriendlyName, &var));
+ VERIFY_ARE_EQUAL(VT_LPWSTR, var.vt);
+ LOG_OUTPUT(L"Testing endpoint: %s", var.pwszVal);
+
+ for (int category = ExtendedAudioCategory_Other; category < ExtendedAudioCategory_enum_count; category++)
+ {
+ if (!(category == ExtendedAudioCategory_FarFieldSpeech ||
+ category == ExtendedAudioCategory_UniformSpeech ||
+ category == ExtendedAudioCategory_VoiceTyping))
+ {
+ wil::com_ptr_nothrow<IAudioClient2> ac;
+ VERIFY_SUCCEEDED(pEndpoint->Activate(__uuidof(IAudioClient2), CLSCTX_ALL, NULL, (void **)&ac));
+
+ AudioClientPropertiesPrivate acpp = {0};
+ acpp.ClientProps.cbSize = sizeof(acpp);
+ acpp.extCategory = (AUDIO_STREAM_EXTENDED_CATEGORY)category;
+
+ VERIFY_SUCCEEDED(ac->SetClientProperties(&acpp.ClientProps));
+
+ wil::unique_cotaskmem_ptr<WAVEFORMATEX> mixFormat;
+ VERIFY_SUCCEEDED(ac->GetMixFormat(wil::out_param(mixFormat)));
+
+ LOG_OUTPUT(L"Testing category: %d", acpp.extCategory);
+ VERIFY_SUCCEEDED(ac->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 0, 0, mixFormat.get(), nullptr));
+
+ Sleep(1000);
+ }
+ }
+ }
+ }
+
+ // Test Capture endpoints - only some stream categories are valid
+ {
+ constexpr AUDIO_STREAM_EXTENDED_CATEGORY captureCategories[] = {ExtendedAudioCategory_Other,
+ ExtendedAudioCategory_Communications,
+ ExtendedAudioCategory_Media,
+ ExtendedAudioCategory_GameChat,
+ ExtendedAudioCategory_Speech,
+ ExtendedAudioCategory_PersonalAssistant,
+ ExtendedAudioCategory_FarFieldSpeech,
+ ExtendedAudioCategory_UniformSpeech,
+ ExtendedAudioCategory_VoiceTyping,
+ };
+
+ wil::com_ptr_nothrow<IMMDeviceCollection> spDevices;
+ VERIFY_SUCCEEDED(spEnumerator->EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE, &spDevices));
+
+ UINT cDevices = 0;
+ VERIFY_SUCCEEDED(spDevices->GetCount(&cDevices));
+
+ for (UINT i = 0; i < cDevices; i++)
+ {
+ wil::com_ptr_nothrow<IMMDevice> pEndpoint;
+ VERIFY_SUCCEEDED(spDevices->Item(i, &pEndpoint));
+
+ wil::unique_prop_variant var;
+ wil::com_ptr_nothrow<IPropertyStore> spPropertyStore;
+ VERIFY_SUCCEEDED(pEndpoint->OpenPropertyStore(STGM_READ, &spPropertyStore));
+ VERIFY_SUCCEEDED(spPropertyStore->GetValue(PKEY_Device_FriendlyName, &var));
+ VERIFY_ARE_EQUAL(VT_LPWSTR, var.vt);
+ LOG_OUTPUT(L"Testing endpoint: %s", var.pwszVal);
+
+ for (int idx = 0; idx < ARRAYSIZE(captureCategories); idx++)
+ {
+ wil::com_ptr_nothrow<IAudioClient2> ac;
+ VERIFY_SUCCEEDED(pEndpoint->Activate(__uuidof(IAudioClient2), CLSCTX_ALL, NULL, (void**)&ac));
+
+ AudioClientPropertiesPrivate acpp = { 0 };
+ acpp.ClientProps.cbSize = sizeof(acpp);
+ acpp.extCategory = captureCategories[idx];
+
+ VERIFY_SUCCEEDED(ac->SetClientProperties(&acpp.ClientProps));
+
+ wil::unique_cotaskmem_ptr<WAVEFORMATEX> mixFormat;
+ VERIFY_SUCCEEDED(ac->GetMixFormat(wil::out_param(mixFormat)));
+
+ LOG_OUTPUT(L"Testing category: %d", acpp.extCategory);
+ VERIFY_SUCCEEDED(ac->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 0, 0, mixFormat.get(), nullptr));
+
+ Sleep(1000);
+ }
+ }
+ }
+
+ // Sleep a while to ensure we receive all the events from the above streams
+ Sleep(5000);
+
+ LOG_OUTPUT(L"Number of audio streams created: %d", parser.GetCountOfAudioClientInits());
+ LOG_OUTPUT(L"Number of audio streams created from AudioDg: %d", parser.GetCountOfAudioClientInitsFromAudioDg());
+ VERIFY_ARE_EQUAL(0, parser.GetCountOfAudioClientInitsFromAudioDg());
+
+ // Stop the trace
+ listener.StopTraceSession();
+
+}
diff --git a/audio/tests/HLK/ThirdPartyApoTests/Wrappers.h b/audio/tests/HLK/ThirdPartyApoTests/Wrappers.h
new file mode 100644
index 00000000..82ceedc0
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/Wrappers.h
@@ -0,0 +1,121 @@
+//
+// Wrappers.h -- Copyright (c) Microsoft Corporation
+//
+// Author: zaneh
+//
+// Description:
+//
+// Wrapper methods for APIs which can throw
+//
+
+// Collects exception data and sends it to Watson without crashing Audio DG.
+// This method can only be called from inside the __except condition statement
+// as a filter function.
+inline DWORD CollectExceptionDataAndContinue(LPEXCEPTION_POINTERS exceptionInfo)
+{
+ LONG lResult;
+ DWORD dwType, dwVal, dwSize=sizeof(DWORD);
+
+ // Check to see if we should allow the process create a crash dump
+ lResult = RegGetValue(HKEY_LOCAL_MACHINE, REGKEY_AUDIO_SOFTWARE, PREVENT_APOTEST_CRASH_OR_REPORT_ON_APO_EXCEPTION, RRF_RT_DWORD, &dwType, &dwVal, &dwSize);
+
+ // If we are allowing dumps, report an exception to Watson before continuing
+ if ((lResult != ERROR_SUCCESS) || (dwVal == 0))
+ {
+ RtlReportException(exceptionInfo->ExceptionRecord, exceptionInfo->ContextRecord, RTL_WER_NO_DEBUG | RTL_WER_NON_FATAL);
+ }
+
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+HRESULT QIInternal(IAudioProcessingObject* pIAPO, _In_ REFIID riid, _COM_Outptr_ void** ppvObject)
+{
+ __try
+ {
+ return pIAPO->QueryInterface(riid, ppvObject);
+ }
+ __except (CollectExceptionDataAndContinue(GetExceptionInformation()))
+ {
+ return __HRESULT_FROM_WIN32(GetExceptionCode());
+ }
+}
+
+HRESULT UnknownQIInternal(IUnknown* pIAPO, _In_ REFIID riid, _COM_Outptr_ void** ppvObject)
+{
+ __try
+ {
+ return pIAPO->QueryInterface(riid, ppvObject);
+ }
+ __except (CollectExceptionDataAndContinue(GetExceptionInformation()))
+ {
+ return __HRESULT_FROM_WIN32(GetExceptionCode());
+ }
+}
+
+HRESULT IsOutputFormatSupported(IAudioProcessingObject* pIAPO, IAudioMediaType* pInputFormat, IAudioMediaType* pRequestedOutputFormat, IAudioMediaType** ppSupportedOutputFormat)
+{
+ __try
+ {
+ return pIAPO->IsOutputFormatSupported(pInputFormat, pRequestedOutputFormat, ppSupportedOutputFormat);
+ }
+ __except (CollectExceptionDataAndContinue(GetExceptionInformation()))
+ {
+ return __HRESULT_FROM_WIN32(GetExceptionCode());
+ }
+}
+
+HRESULT LockForProcess(IAudioProcessingObjectConfiguration* pIAPOConfig,
+ _In_ UINT32 u32NumInputConnections,
+ _In_reads_(u32NumInputConnections) APO_CONNECTION_DESCRIPTOR** ppInputConnections,
+ _In_ UINT32 u32NumOutputConnections,
+ _In_reads_(u32NumOutputConnections) APO_CONNECTION_DESCRIPTOR** ppOutputConnections)
+{
+ __try
+ {
+ return pIAPOConfig->LockForProcess(u32NumInputConnections, ppInputConnections, u32NumOutputConnections, ppOutputConnections);
+ }
+ __except (CollectExceptionDataAndContinue(GetExceptionInformation()))
+ {
+ return __HRESULT_FROM_WIN32(GetExceptionCode());
+ }
+}
+
+HRESULT UnlockForProcess(IAudioProcessingObjectConfiguration* pIAPOConfig)
+{
+ __try
+ {
+ return pIAPOConfig->UnlockForProcess();
+ }
+ __except (CollectExceptionDataAndContinue(GetExceptionInformation()))
+ {
+ return __HRESULT_FROM_WIN32(GetExceptionCode());
+ }
+}
+
+void APOProcess(IAudioProcessingObjectRT* pIAPORT,
+ _In_ UINT32 u32NumInputConnections,
+ _In_reads_(u32NumInputConnections) APO_CONNECTION_PROPERTY** ppInputConnections,
+ _In_ UINT32 u32NumOutputConnections,
+ _Inout_updates_(u32NumOutputConnections) APO_CONNECTION_PROPERTY** ppOutputConnections)
+{
+ __try
+ {
+ pIAPORT->APOProcess(u32NumInputConnections, ppInputConnections, u32NumOutputConnections, ppOutputConnections);
+ }
+ __except (CollectExceptionDataAndContinue(GetExceptionInformation()))
+ {
+ return;
+ }
+}
+
+HRESULT GetRegistrationProperties(IAudioProcessingObject* pIAPO, APO_REG_PROPERTIES** ppRegProps)
+{
+ __try
+ {
+ return pIAPO->GetRegistrationProperties(ppRegProps);
+ }
+ __except (CollectExceptionDataAndContinue(GetExceptionInformation()))
+ {
+ return __HRESULT_FROM_WIN32(GetExceptionCode());
+ }
+} \ No newline at end of file
diff --git a/audio/tests/HLK/ThirdPartyApoTests/audioconnectionutil.h b/audio/tests/HLK/ThirdPartyApoTests/audioconnectionutil.h
new file mode 100644
index 00000000..771d03de
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/audioconnectionutil.h
@@ -0,0 +1,129 @@
+#pragma once
+
+#define IS_2_POW_N(X) (((X)&(X-1)) == 0)
+
+enum class aligned_size_t : size_t {};
+
+void * AllocateAligned(size_t cb, aligned_size_t AlignmentMask)
+{
+ ASSERT(0 != cb);
+ //ASSERT(IS_2_POW_N(AlignmentMask + 1));
+
+ void *res = _aligned_malloc(cb, static_cast<size_t>(AlignmentMask) + 1);
+
+ return res;
+}
+
+void DeallocateAligned(void * p, aligned_size_t /* AlignmentMask */)
+{
+ if (NULL != p)
+ {
+ _aligned_free(p);
+ }
+}
+
+UINT32 CalculateAlignmentMask(APO_CONNECTION_DESCRIPTOR * /* pDescriptor */, UINT32 u32BytesPerFrame)
+{
+ const UINT32 u32AudioAlignment = sizeof(PVOID);
+ UINT32 u32Alignment = u32AudioAlignment - 1;
+
+ // Calculate the new alignment requirement for this buffer.
+ if (u32BytesPerFrame > u32AudioAlignment)
+ {
+ // Use the frame size directly if it is a power of two.
+ if (IS_2_POW_N(u32BytesPerFrame))
+ {
+ u32Alignment = u32BytesPerFrame - 1;
+ }
+ // The new alignment size should be greater than frame
+ // size and should be a power of 2.
+ else
+ {
+ u32Alignment = u32AudioAlignment;
+ while (u32BytesPerFrame / u32Alignment)
+ {
+ u32Alignment *= 2;
+ }
+ u32Alignment = u32Alignment - 1;
+ }
+ }
+
+ // Use default alignment if the frame size is less than the default
+ // alignment.
+ return u32Alignment;
+} // CalculateAlignmentMask
+
+HRESULT
+CreateConnection(APO_CONNECTION_DESCRIPTOR* pDescriptor, APO_CONNECTION_PROPERTY* pProperty)
+{
+ RETURN_HR_IF_NULL(E_POINTER, pDescriptor);
+ RETURN_HR_IF_NULL(E_POINTER, pDescriptor->pFormat);
+ RETURN_HR_IF_NULL(E_POINTER, pProperty);
+
+ UINT32 u32BytesPerFrame;
+ unsigned byteAlignmentMask;
+ BYTE* pAllocatedBuffer;
+ UNCOMPRESSEDAUDIOFORMAT Format;
+
+ RETURN_IF_FAILED(pDescriptor->pFormat->GetUncompressedAudioFormat(&Format));
+
+ u32BytesPerFrame =
+ Format.dwSamplesPerFrame * Format.dwBytesPerSampleContainer;
+
+ // Allocate buffer internally.
+ if (NULL == pDescriptor->pBuffer)
+ {
+ byteAlignmentMask = CalculateAlignmentMask(pDescriptor, u32BytesPerFrame);
+
+ pAllocatedBuffer = (BYTE *)AllocateAligned(pDescriptor->u32MaxFrameCount * u32BytesPerFrame, static_cast<aligned_size_t>(byteAlignmentMask));
+ RETURN_HR_IF_NULL(E_OUTOFMEMORY, pAllocatedBuffer);
+
+ pDescriptor->pBuffer = reinterpret_cast<UINT_PTR>(pAllocatedBuffer);
+ pDescriptor->Type = APO_CONNECTION_BUFFER_TYPE_ALLOCATED;
+ }
+ // Use the given buffer.
+ else
+ {
+ pDescriptor->Type = APO_CONNECTION_BUFFER_TYPE_EXTERNAL;
+ }
+
+ pProperty->pBuffer = pDescriptor->pBuffer;
+ pProperty->u32ValidFrameCount = 0;
+ pProperty->u32Signature = APO_CONNECTION_PROPERTY_SIGNATURE;
+
+ return S_OK;
+} // CreateConnection
+
+HRESULT
+DestroyConnection(APO_CONNECTION_DESCRIPTOR *pDescriptor)
+{
+ HRESULT hResult;
+ UINT32 u32BytesPerFrame;
+ size_t byteAlignmentMask;
+ BYTE* pAllocatedBuffer;
+ UNCOMPRESSEDAUDIOFORMAT Format;
+
+ hResult = pDescriptor->pFormat->GetUncompressedAudioFormat(&Format);
+ //IF_FAILED_JUMP(hResult, Exit);
+
+ if (APO_CONNECTION_BUFFER_TYPE_ALLOCATED == pDescriptor->Type)
+ {
+ u32BytesPerFrame =
+ Format.dwSamplesPerFrame * Format.dwBytesPerSampleContainer;
+
+ byteAlignmentMask = CalculateAlignmentMask(pDescriptor, u32BytesPerFrame);
+
+ if (pDescriptor->pBuffer)
+ {
+ pAllocatedBuffer = reinterpret_cast<BYTE*>(pDescriptor->pBuffer);
+ RETURN_HR_IF_NULL(E_OUTOFMEMORY, pAllocatedBuffer);
+
+ DeallocateAligned((void *) pAllocatedBuffer, static_cast<aligned_size_t>(byteAlignmentMask));
+ }
+ }
+
+ pDescriptor->pFormat->Release();
+ pDescriptor->pFormat = NULL;
+
+ return hResult;
+} // DestroyConnection
diff --git a/audio/tests/HLK/ThirdPartyApoTests/sinewave.h b/audio/tests/HLK/ThirdPartyApoTests/sinewave.h
new file mode 100644
index 00000000..8f0fc03c
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/sinewave.h
@@ -0,0 +1,60 @@
+#pragma once
+
+class SineWave
+{
+ struct wave
+ {
+ float amp{}, freq{}, phase{}, dc{};
+ };
+public:
+ SineWave() {}
+
+ template<typename _ty1, typename _ty2>
+ SineWave(_ty1 numChannels, _ty2 samplingRate) : _channel(unsigned(numChannels)), _sr(float(samplingRate)) {}
+
+ template<typename _ty1, typename _ty2>
+ inline void Initialize(_ty1 numChannels, _ty2 samplingRate)
+ {
+ _channel.resize(unsigned(numChannels));
+ _sr = unsigned(samplingRate);
+ }
+
+ template<typename _ty1>
+ inline void SetChannel(_ty1 channel, float freq, float amplitude = 0.f, float dc = 0.f, float phase = 0.f)
+ {
+ _channel[unsigned(channel)].amp = amplitude;
+ _channel[unsigned(channel)].freq = freq;
+ _channel[unsigned(channel)].phase = phase;
+ _channel[unsigned(channel)].dc = dc;
+ }
+
+
+ template<typename _ty1>
+ void FillFrames(void* buffer, _ty1 numFrames)
+ {
+ auto fb = reinterpret_cast<float*>(buffer);
+ for (unsigned i = 0; i < unsigned(numFrames); ++i)
+ {
+ for (unsigned ch = 0; ch < _channel.size(); ++ch)
+ {
+ fb[i * _channel.size() + ch] = Calculate(ch);
+ }
+ }
+ }
+
+protected:
+ float Calculate(unsigned ch)
+ {
+ auto& w = _channel[ch];
+ float sample = w.amp * sinf(w.phase) + w.dc;
+
+ w.phase += 2 * float(M_PI) * w.freq / _sr;
+ w.phase = fmodf(w.phase, 2 * float(M_PI));
+
+ return sample;
+ }
+
+private:
+ std::vector<wave> _channel;
+ float _sr{};
+}; \ No newline at end of file
diff --git a/audio/tests/HLK/ThirdPartyApoTests/stdafx.h b/audio/tests/HLK/ThirdPartyApoTests/stdafx.h
new file mode 100644
index 00000000..8a836cf0
--- /dev/null
+++ b/audio/tests/HLK/ThirdPartyApoTests/stdafx.h
@@ -0,0 +1,123 @@
+//
+// stdafx.h -- Copyright (c) Microsoft Corporation
+//
+// Author: zaneh
+//
+// Description:
+//
+// Include file for well-known headers
+//
+#pragma once
+
+#define _USE_MATH_DEFINES
+#include <cmath>
+#include <vector>
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#define NO_MOCK_VALIDATION
+#include <mock.h>
+#include <Windows.Media.Devices.h>
+#include <windows.h>
+#include <versionhelpers.h>
+#include <WexTestClass.h>
+
+#include "wil\resource.h"
+#include "wil\com.h"
+
+
+// System Effect Specifiers. These help determine which type of system
+// effect the device is attempting to use in order to test it properly
+#define DT_GFX 0x00000002
+#define DT_LFX 0x00000004
+#define DT_LGFX (DT_LFX | DT_GFX)
+#define DT_SFX 0x00000008
+#define DT_MFX 0x00000010
+#define DT_EFX 0x00000020
+#define DT_SMEFX (DT_SFX | DT_MFX | DT_EFX)
+
+// Reg Key definitions for disabling AudioDG crashing on an APO exception
+#define PREVENT_APOTEST_CRASH_OR_REPORT_ON_APO_EXCEPTION L"PreventAPOTestCrashOrReportOnAPOException"
+#define REGKEY_AUDIO_SOFTWARE L"Software\\Microsoft\\Windows\\CurrentVersion\\Audio"
+#define REGKEY_DEFAULT L"(default)"
+
+// Test logging macros
+#ifndef LOG_ERROR
+#define LOG_ERROR(fmt, ...) WEX::Logging::Log::Error(WEX::Common::String().Format(fmt L"\n\t\tFunction: " \
+ __FUNCTION__ L" Line: %d", __VA_ARGS__, __LINE__))
+#endif
+
+#ifndef LOG_OUTPUT
+#define LOG_OUTPUT(fmt, ...) WEX::Logging::Log::Comment(WEX::Common::String().Format(fmt, __VA_ARGS__))
+#endif
+
+#define LOG_RETURN_IF_FAILED(hr, fmt, ...) if (FAILED(hr)) { LOG_ERROR(fmt, __VA_ARGS__); \
+ WEX::Logging::Log::Error(WEX::Common::String().Format(L"\t\tError Code: (0x%08lx)" \
+ , hr)); return hr; }
+#define LOG_RETURN_VOID_IF_FAILED(hr, fmt, ...) if(FAILED(hr)) { LOG_ERROR(fmt, __VA_ARGS__); \
+ WEX::Logging::Log::Error(WEX::Common::String().Format(L"\t\tError Code: (0x%08lx)" \
+ , hr)); return; }
+#define LOG_RETURN_HR_IF(condition, hr, fmt, ...) if (condition) { LOG_ERROR(fmt, __VA_ARGS__); \
+ WEX::Logging::Log::Error(WEX::Common::String().Format(L"\t\tError Code: (0x%08lx)" \
+ , hr)); return hr; }
+// End Test logging macros
+
+// Begin Metadata defines
+#define COMMON_ONECORE_TEST_PROPERTIES \
+ COMMON_TEST_PROPERTIES \
+ TEST_METHOD_PROPERTY(L"Kits.SupportedOS", L"Windows v10.0 Client x86") \
+ TEST_METHOD_PROPERTY(L"Kits.SupportedOS", L"Windows v10.0 Client x64") \
+ TEST_METHOD_PROPERTY(L"Kits.SupportedOS", L"Windows v10.0 Client ARM") \
+ TEST_METHOD_PROPERTY(L"Kits.SupportedOS", L"Windows v10.0 Client ARM64") \
+ TEST_METHOD_PROPERTY(L"Kits.MinRelease", L"RS5") \
+ TEST_METHOD_PROPERTY(L"Kits.CorePackageComposition", L"OneCoreUAP") \
+ TEST_METHOD_PROPERTY(L"Kits.CorePackageComposition", L"OneCore") \
+ TEST_METHOD_PROPERTY(L"Kits.CorePackageComposition", L"Full") \
+
+#define COMMON_TEST_PROPERTIES \
+ TEST_METHOD_PROPERTY(L"Kits.TestType", L"Development") \
+ TEST_METHOD_PROPERTY(L"Kits.RunElevated", L"True") \
+ TEST_METHOD_PROPERTY(L"Kits.RequiresReboot", L"False") \
+ TEST_METHOD_PROPERTY(L"Kits.PublishingOrganization", L"Microsoft Corporation") \
+ TEST_METHOD_PROPERTY(L"Kits.DevelopmentPhase", L"Development and Integration") \
+ TEST_METHOD_PROPERTY(L"Kits.HasSupplementalContent", L"False") \
+
+#define APO_TEST_PROPERTIES \
+ TEST_METHOD_PROPERTY(L"Kits.Specification", L"Device.Audio.APO.ThirdParty") \
+
+#define START_APPVERIFIFER \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask", L"AppVerifierStart") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.AppVerifierStart.Stage", L"Setup") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.AppVerifierStart.RunElevated", L"True") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.AppVerifierStart.CommandLine", L"cmd.exe /c appverif -enable exceptions handles heaps leak locks memory srwlock threadpool tls -for te.processhost.exe te.exe audiodg.exe") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.AppVerifierStart.Order", L"1") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.AppVerifierStart.ExpectedExitCode", L"0") \
+
+#define END_APPVERIFIER \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask", L"AppVerifierEnd") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.AppVerifierEnd.Stage", L"Cleanup") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.AppVerifierEnd.RunElevated", L"True") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.AppVerifierEnd.CommandLine", L"cmd.exe /c appverif -disable exceptions handles heaps leak locks memory srwlock threadpool tls -for te.processhost.exe te.exe audiodg.exe") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.AppVerifierEnd.Order", L"1") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.AppVerifierEnd.ExpectedExitCode", L"0") \
+
+#define START_OSUPGRADE \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask", L"OSUpgrade") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.OSUpgrade.Stage", L"Setup") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.OSUpgrade.RunElevated", L"True") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.OSUpgrade.CommandLine", L"cmd.exe /c c:\\HLK\\ISO\\setup.exe /auto:upgrade /compat IgnoreWarning /noreboot") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.OSUpgrade.Order", L"1") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.OSUpgrade.ExpectedExitCode", L"0") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.OSUpgrade.TimeoutInMinutes", L"240") \
+
+#define START_APPVERIFIFER_UPGRADE \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask", L"AppVerifierStart") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.AppVerifierStart.Stage", L"Setup") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.AppVerifierStart.RunElevated", L"True") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.AppVerifierStart.CommandLine", L"cmd.exe /c appverif -enable exceptions handles heaps leak locks memory srwlock threadpool tls -for te.processhost.exe te.exe audiodg.exe") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.AppVerifierStart.Order", L"2") \
+ TEST_CLASS_PROPERTY(L"Kits.TestTask.AppVerifierStart.ExpectedExitCode", L"0") \
+
+// End Metadata defines
diff --git a/audio/tests/KSPosTst/KsPosTestTaef.cpp b/audio/tests/KSPosTst/KsPosTestTaef.cpp
new file mode 100644
index 00000000..b92f9e4f
--- /dev/null
+++ b/audio/tests/KSPosTst/KsPosTestTaef.cpp
@@ -0,0 +1,215 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// File Name:
+//
+// KsPosTestTaef.cpp
+//
+// Abstract:
+//
+// Implementation file for KsPosTestTaef
+//
+// -------------------------------------------------------------------------------
+#include "PreComp.h"
+#include "KsPosTestTaef.h"
+#include "tests.h"
+
+using namespace WEX::Common;
+using namespace WEX::Logging;
+using namespace WEX::TestExecution;
+
+#define RUN_TEST_CASE(testfn) \
+{ \
+ SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures); \
+ testfn(); \
+}
+
+IBasicLog * g_pBasicLog = NULL;
+WDMAudio::KsPosTest* g_pKsPosTst = NULL;
+
+TIMER_MECHANISM g_Timer =
+{
+ tpQPC, "QueryPerformanceCounter"
+};
+
+void LogWaveFormat(WAVEFORMATEX* pwfx)
+{
+ WAVEFORMATEXTENSIBLE* wfex = (WAVEFORMATEXTENSIBLE*)pwfx;
+
+ switch (pwfx->wFormatTag)
+ {
+ case WAVE_FORMAT_PCM:
+ LOG(g_pBasicLog, L" wFormatTag = WAVE_FORMAT_PCM");
+ break;
+ case WAVE_FORMAT_IEEE_FLOAT:
+ LOG(g_pBasicLog, L" wFormatTag = WAVE_FORMAT_IEEE_FLOAT");
+ break;
+ case WAVE_FORMAT_EXTENSIBLE:
+ LOG(g_pBasicLog, L" wFormatTag = WAVE_FORMAT_EXTENSIBLE");
+ if (wfex->SubFormat.Data1 == WAVE_FORMAT_PCM)
+ LOG(g_pBasicLog, L" SubFormat = WAVE_FORMAT_PCM");
+ if (wfex->SubFormat.Data1 == WAVE_FORMAT_IEEE_FLOAT)
+ LOG(g_pBasicLog, L" SubFormat = WAVE_FORMAT_IEEE_FLOAT");
+ break;
+ default:
+ LOG(g_pBasicLog, L" wFormatTag = UNKNOWN!");
+ }
+ LOG(g_pBasicLog, L" nChannel = %d", pwfx->nChannels);
+ LOG(g_pBasicLog, L" nSamplesPerSec = %d", pwfx->nSamplesPerSec);
+ LOG(g_pBasicLog, L" nAvgBytesPerSe = %d", pwfx->nAvgBytesPerSec);
+ LOG(g_pBasicLog, L" nBlockAlign = %d", pwfx->nBlockAlign);
+ LOG(g_pBasicLog, L" wBitsPerSample = %d", pwfx->wBitsPerSample);
+
+
+ if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
+ {
+ LOG(g_pBasicLog, L" wValidBitsPerSample = %d", wfex->Samples.wValidBitsPerSample);
+ LOG(g_pBasicLog, L" dwChannelMask = %hd", wfex->dwChannelMask);
+ }
+}
+
+// -------------------------------------------------------------------------------
+namespace WDMAudio
+{
+ BEGIN_MODULE()
+ MODULE_PROPERTY(L"Feature", L"PortCls HCK Tests")
+ MODULE_PROPERTY(L"TestResourceDependent", L"true")
+ END_MODULE()
+
+ // Create WEXBasicLog, Coinitialize Etc
+ MODULE_SETUP(WDMAudioSetup)
+
+ // Release stuff acquired in WDMAudioSetup
+ MODULE_CLEANUP(WDMAudioCleanup)
+};
+
+bool WDMAudio::WDMAudioSetup()
+{
+ if (NULL == g_pBasicLog)
+ {
+ if (!(VERIFY_SUCCEEDED(CreateWexBasicLog(&g_pBasicLog))))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool WDMAudio::WDMAudioCleanup()
+{
+ if (g_pBasicLog)
+ {
+ g_pBasicLog->Release();
+ }
+
+ return true;
+}
+
+// -------------------------------------------------------------------------------
+bool WDMAudio::KsPosTest::KsPosTestSetup()
+{
+ g_pKsPosTst = this;
+ m_pTimer = &g_Timer;
+ // The histograms can be displayed by using the command line parameter checked below
+ // If the parameter is not specified, the default is to not log anything
+ bool param = true;
+ WEX::TestExecution::RuntimeParameters::TryGetValue(L"logHistograms", param);
+ m_fLogHistograms = param;
+ return true;
+}
+
+bool WDMAudio::KsPosTest::KsPosTestCleanUp()
+{
+ g_pKsPosTst = NULL;
+
+ return true;
+}
+
+// -------------------------------------------------------------------------------
+bool WDMAudio::KsPosTest::TestCaseSetup()
+{
+ CComPtr<ITestResource> spResource;
+ CComQIPtr<IHalfAppContainer> spHalfContainer;
+
+ SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures);
+
+ Log::Comment(L"");
+ Log::Comment(L"------------------------------------------------------");
+ Log::Comment(L"Running test case setup");
+
+ size_t count = Resources::Count();
+ if (!VERIFY_ARE_EQUAL(count, (size_t)1)) { return false; }
+ if (!VERIFY_SUCCEEDED(Resources::Item(0, &spResource))) { return false; }
+
+ // 1. Assign m_pHalf
+ spHalfContainer = spResource;
+ if (!VERIFY_IS_NOT_NULL(spHalfContainer)) { return false; }
+ if (!VERIFY_SUCCEEDED(spHalfContainer->GetHalfApp(&m_pHalf))) { return false; }
+
+ // 2. Check if this is a loopback pin. If so, assign the host pin's HalfApp
+ if (m_pHalf->m_ConnectorType == eLoopbackConnector)
+ {
+ VERIFY_SUCCEEDED(m_pHalf->GetHostHalfApp(&m_pHostHalf));
+ }
+ else
+ {
+ m_pHostHalf = NULL;
+ }
+
+ Log::Comment(L"The test will run on the following format:");
+ if (m_pHostHalf != NULL)
+ {
+ LogWaveFormat(m_pHostHalf->m_pCurrentFormat.get());
+ }
+ else
+ {
+ LogWaveFormat(m_pHalf->m_pCurrentFormat.get());
+ }
+
+ return true;
+}
+
+bool WDMAudio::KsPosTest::TestCaseCleanUp()
+{
+ // Stop the timer here, in case any latency test fails
+ NtSetTimerResolution(0, FALSE, &actualTimerResolution);
+
+ if (!CompareWaveFormat(m_pHalf->m_pCurrentFormat.get(), m_pHalf->m_pPreferredFormat.get())) {
+ CloneWaveFormat(m_pHalf->m_pPreferredFormat.get(), wil::out_param(m_pHalf->m_pCurrentFormat));
+ m_pHalf->m_u32CurrentDefaultPeriodicityInFrames = m_pHalf->m_u32DefaultPeriodicityInFrames;
+ m_pHalf->m_u32CurrentFundamentalPeriodicityInFrames = m_pHalf->m_u32FundamentalPeriodicityInFrames;
+ m_pHalf->m_u32CurrentMinPeriodicityInFrames = m_pHalf->m_u32MinPeriodicityInFrames;
+ m_pHalf->m_u32CurrentMaxPeriodicityInFrames = m_pHalf->m_u32MaxPeriodicityInFrames;
+ }
+
+ if (m_pHostHalf != NULL) {
+ if (!VERIFY_SUCCEEDED(m_pHostHalf->CleanupStream())) { return false; }
+ if (!VERIFY_SUCCEEDED(m_pHostHalf->ReleaseEndpoint())) { return false; }
+ if (!VERIFY_SUCCEEDED(m_pHostHalf->ReleaseSineToneDataBuffer())) { return false; }
+ delete m_pHostHalf;
+ m_pHostHalf = NULL;
+ }
+
+ if (m_pHalf != NULL) {
+ if (!VERIFY_SUCCEEDED(m_pHalf->CleanupStream())) { return false; }
+ if (!VERIFY_SUCCEEDED(m_pHalf->ReleaseEndpoint())) { return false; }
+ if (!VERIFY_SUCCEEDED(m_pHalf->ReleaseSineToneDataBuffer())) { return false; }
+
+ m_pHalf = NULL;
+ }
+
+ return true;
+}
+
+// -------------------------------------------------------------------------------
+void WDMAudio::KsPosTest::TAEF_DriftAndJitter()
+{
+ RUN_TEST_CASE(Test_DriftAndJitter_Default);
+}
+
+void WDMAudio::KsPosTest::TAEF_Latency()
+{
+ RUN_TEST_CASE(Test_Latency_Default);
+}
diff --git a/audio/tests/KSPosTst/PreComp.h b/audio/tests/KSPosTst/PreComp.h
new file mode 100644
index 00000000..5fdfc9db
--- /dev/null
+++ b/audio/tests/KSPosTst/PreComp.h
@@ -0,0 +1,108 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// File Name:
+//
+// PreComp.h
+//
+// Abstract:
+//
+// Precompiled common headers
+//
+// -------------------------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// Number of milliseconds that the test will be delayed to wait for the stream to stabilize
+#define DELAY_FOR_STABILIZE 100
+
+// Number of milliseconds in a second
+#define MILLISECONDS_PER_SECOND 1000
+
+// Number of HNS units in one second
+#define HNSTIME_UNITS_PER_SECOND 10000000
+
+// Number of HNS units in one millisecond
+#define HNSTIME_UNITS_PER_MILLISECOND 10000
+
+typedef double (*TIMEPROC) (void);
+double tpQPC(void);
+
+typedef struct _tag_tm
+{
+ TIMEPROC Proc;
+ LPCSTR strRep;
+} TIMER_MECHANISM, * PTIMER_MECHANISM;
+
+// ----------------------------------------------------------
+// Timer functions
+extern "C" __kernel_entry NTSYSCALLAPI NTSTATUS NTAPI NtSetTimerResolution(
+ _In_ ULONG DesiredTime, _In_ BOOLEAN SetResolution, _Out_ PULONG ActualTime);
+
+// 1 ms timer resolution
+static ULONG timerResolution = (1 * 10000);
+static ULONG actualTimerResolution;
+
+// ------------------------------------------------------------------------------
+// structs used to hold results of perf tests
+#define DATA_POINTS 100
+
+typedef struct
+{
+ double testTime; // Time the sample was taken, in milliseconds, relative to the start of the sample collection
+ double positionTime; // Time of the reported position, in milliseconds, relative to the start of the sample collection
+ double position; // Position, in seconds, relative to the start of the sample collection
+} POSITION_SET, * PPOSITION_SET;
+
+typedef struct
+{
+ PPOSITION_SET argPosSets;
+ ULONG cPosSets;
+ ULONG ctLatencyMeas;
+ ULONG csBufferMeas;
+ double bytesPerSecond; // measured (in bytes/sec, NOT samples/sec)
+ double dOffset; // measured
+} PERF_RESULTS, * PPERF_RESULTS;
+
+typedef struct
+{
+ WAVEFORMATEXTENSIBLE wfxFormat;
+ PERF_RESULTS perfResults; //
+} FORMAT_ENTRY, * PFORMAT_ENTRY;
diff --git a/audio/tests/KSPosTst/TestResourceBuild.cpp b/audio/tests/KSPosTst/TestResourceBuild.cpp
new file mode 100644
index 00000000..93959089
--- /dev/null
+++ b/audio/tests/KSPosTst/TestResourceBuild.cpp
@@ -0,0 +1,522 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// File Name:
+//
+// TestResourceBuild.cpp
+//
+// Abstract:
+//
+// TAEF BuildResourceList implementation
+//
+// ------------------------------------------------------------------------------
+#include "PreComp.h"
+#include <TestResource.h>
+#include <PropertyHelper.h>
+
+using namespace WEX::Common;
+using namespace WEX::Logging;
+using namespace WEX::TestExecution;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// CreateTestResource
+//
+// Create the test resource with MMDevice, device id, device name, data flow, connector type, connector id, mode,
+// list of formats
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT CreateTestResource
+(
+ ResourceList& resourceList,
+ DeviceDescriptor descriptor
+)
+{
+ HRESULT hr = S_OK;
+
+ CComHeapPtr<CHalfApp> spHalfApp;
+ wil::com_ptr_nothrow<ITestResource> spTestResource;
+ GUID ResourceGUID;
+ CComBSTR szResourceName;
+
+ // Create HalfApp
+ spHalfApp.Attach(new CHalfApp(descriptor));
+ if (!VERIFY_IS_NOT_NULL(spHalfApp)) {
+ hr = E_OUTOFMEMORY;
+ return hr;
+ }
+
+ // Create PinTestResource
+ if (!VERIFY_SUCCEEDED(hr = CoCreateGuid(&ResourceGUID))) {
+ return hr;
+ }
+ if (!VERIFY_SUCCEEDED(hr = CPinTestResource::CreateInstance(
+ spHalfApp, ResourceGUID, &spTestResource))) {
+ return hr;
+ }
+
+ // Add to resource list
+ spHalfApp.Detach();
+ if (!VERIFY_SUCCEEDED(hr = resourceList.Add(spTestResource.get()))) {
+ return hr;
+ }
+ if (!VERIFY_SUCCEEDED(hr = spTestResource->GetValue(CComBSTR(TestResourceProperty::c_szName), &szResourceName))) {
+ return hr;
+ }
+ Log::Comment(String().Format(L"Test Resource (%s) added", (PCWSTR)szResourceName));
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// GetProcessingModesForConnector
+//
+// For host/keyword detector pin, processing mode info is cached in property store and can be directly read. For offload
+// pin, query for ks processing mode property. For loopback pin, it doesn't support any processing modes, return GUID_NULL.
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT GetProcessingModesForConnector
+(
+ IMMDevice* pDevice,
+ UINT uConnectorId,
+ EndpointConnectorType eConnectorType,
+ ULONG *pCount,
+ AUDIO_SIGNALPROCESSINGMODE **ppModes
+)
+{
+ HRESULT hr = S_OK;
+
+ *pCount = 0;
+ *ppModes = NULL;
+
+ if (eConnectorType == eHostProcessConnector || eConnectorType == eKeywordDetectorConnector) {
+ if (!VERIFY_SUCCEEDED(hr = GetCachedProcessingModes(pDevice, eConnectorType, pCount, ppModes))) {
+ return hr;
+ }
+ }
+ else if (eConnectorType == eOffloadConnector) {
+ if (!VERIFY_SUCCEEDED(hr = GetProcessingModes(pDevice, uConnectorId, pCount, ppModes))) {
+ return hr;
+ }
+ }
+ else if (eConnectorType == eLoopbackConnector) {
+ // Loopback pin doesn't support any processing modes, so put 1 GUID_NULL
+ CComHeapPtr<AUDIO_SIGNALPROCESSINGMODE> spModes;
+
+ if (!spModes.Allocate(1))
+ return E_OUTOFMEMORY;
+
+ spModes[0] = GUID_NULL;
+
+ *pCount = 1;
+ *ppModes = spModes.Detach();
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// GetDefaultFormatForConnector
+//
+// Read audio engine device format from property store as default format.
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT GetDefaultFormatForConnector
+(
+ IMMDevice* pDevice,
+ EndpointConnectorType eConnectorType,
+ WAVEFORMATEX **ppDefaultFormat
+)
+{
+ HRESULT hr = S_OK;
+
+ *ppDefaultFormat = NULL;
+ if (!VERIFY_SUCCEEDED(hr = GetCachedDefaultFormat(pDevice, eConnectorType, ppDefaultFormat))){
+ return hr;
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// GetSupportedFormatsForConnector
+//
+// For host/keyword detector pin, supported formats info is cached in property store and can be directly read. For offload
+// pin, provide with a predefined list of formats and check whether format is supported. For loopback pin, it matches the format
+// of host pin so put 0 format record.
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT GetSupportedFormatRecordsForConnector
+(
+ IMMDevice* pDevice,
+ UINT uConnectorId,
+ EndpointConnectorType eConnectorType,
+ AUDIO_SIGNALPROCESSINGMODE mode,
+ STACKWISE_DATAFLOW dataFlow,
+ ULONG *pCount,
+ FORMAT_RECORD **ppFormatRecords
+)
+{
+ HRESULT hr = S_OK;
+
+ *pCount = 0;
+ *ppFormatRecords = NULL;
+
+ if (eConnectorType == eHostProcessConnector || eConnectorType == eKeywordDetectorConnector) {
+ if (!VERIFY_SUCCEEDED(hr = GetCachedSupportedFormatRecords(pDevice, eConnectorType, mode, pCount, ppFormatRecords))) {
+ return hr;
+ }
+ }
+ else if (eConnectorType == eOffloadConnector) {
+ if (!VERIFY_SUCCEEDED(hr = GetSupportedFormatRecords(pDevice, uConnectorId, eConnectorType, mode, dataFlow, pCount, ppFormatRecords))) {
+ return hr;
+ }
+ }
+ else if (eConnectorType == eLoopbackConnector) {
+ *pCount = 0;
+ *ppFormatRecords = NULL;
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// GetPreferredFormatForConnector
+//
+// If KSPROPERTY_PIN_PROPOSEDATAFORMAT2 is supported, use the proposed format for mode as preferred format for mode.
+// Otherwise, use default format as preferred format.
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT GetPreferredFormatForConnector
+(
+ IMMDevice* pDevice,
+ UINT uConnectorId,
+ EndpointConnectorType eConnectorType,
+ AUDIO_SIGNALPROCESSINGMODE mode,
+ WAVEFORMATEX **ppPreferredFormat
+)
+{
+ HRESULT hr = S_OK;
+ wil::unique_cotaskmem_ptr<WAVEFORMATEX> pDefaultFormat;
+ wil::unique_cotaskmem_ptr<WAVEFORMATEX> pProposedFormat;
+
+ *ppPreferredFormat = NULL;
+
+
+ // Get default format for connector
+ if (!VERIFY_SUCCEEDED(hr = GetDefaultFormatForConnector(pDevice, eConnectorType, wil::out_param(pDefaultFormat)))) {
+ return hr;
+ }
+
+ // Return the processing mode specific format proposed by the driver
+ hr = GetProposedFormatForProcessingMode(pDevice, uConnectorId, mode, wil::out_param(pProposedFormat));
+ if (hr == S_OK) {
+ CloneWaveFormat(pProposedFormat.get(), ppPreferredFormat);
+ }
+ else {
+ CloneWaveFormat(pDefaultFormat.get(), ppPreferredFormat);
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// GetPreferredFormatPeriodicityCharacteristicsForConnector
+//
+// Get periodicity characteristics for format. For host/keyword detector pin, periodicity info is cached along with format
+// in property store and can be searched from supported format list. For offload pin, it should be calculate from
+// DiscoverPeriodicityCharacteristicsForFormat.
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT GetPreferredFormatPeriodicityCharacteristicsForConnector
+(
+ IMMDevice* pDevice,
+ EndpointConnectorType eConnectorType,
+ AUDIO_SIGNALPROCESSINGMODE mode,
+ STACKWISE_DATAFLOW dataFlow,
+ WAVEFORMATEX *pPreferredFormat,
+ ULONG cFormatRecords,
+ PFORMAT_RECORD pFormatRecords,
+ UINT32 *pDefaultPeriodicityInFrames,
+ UINT32 *pFundamentalPeriodicityInFrames,
+ UINT32 *pMinPeriodicityInFrames,
+ UINT32 *pMaxPeriodicityInFrames,
+ UINT32 *pMaxPeriodicityInFramesExtended
+)
+{
+ HRESULT hr = S_OK;
+ bool bFormatInList = false;
+
+ for (ULONG i = 0; i < cFormatRecords; i++) {
+ if (CompareWaveFormat((WAVEFORMATEX *)&pFormatRecords[i].wfxEx, pPreferredFormat)) {
+ bFormatInList = true;
+ *pDefaultPeriodicityInFrames = pFormatRecords[i].defaultPeriodInFrames;
+ *pFundamentalPeriodicityInFrames = pFormatRecords[i].fundamentalPeriodInFrames;
+ *pMinPeriodicityInFrames = pFormatRecords[i].minPeriodInFrames;
+ *pMaxPeriodicityInFrames = pFormatRecords[i].maxPeriodInFrames;
+ *pMaxPeriodicityInFramesExtended = pFormatRecords[i].maxPeriodInFramesExtended;
+ break;
+ }
+ }
+
+ if (eConnectorType == eHostProcessConnector || eConnectorType == eKeywordDetectorConnector) {
+ if (!VERIFY_IS_TRUE(bFormatInList)) {
+ hr = E_NOTFOUND;
+ return hr;
+ }
+ }
+ else if (eConnectorType == eOffloadConnector || eConnectorType == eLoopbackConnector) {
+ if (!VERIFY_SUCCEEDED(hr = DiscoverPeriodicityCharacteristicsForFormat(pDevice, eConnectorType, mode, pPreferredFormat, dataFlow, pDefaultPeriodicityInFrames, pFundamentalPeriodicityInFrames, pMinPeriodicityInFrames, pMaxPeriodicityInFrames, pMaxPeriodicityInFramesExtended))) {
+ return hr;
+ }
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// AddTestResourceForConnector
+//
+// For each connector, read connector id, get all processing modes, identify default and preferred format for each mode
+// and also enumerate a list of supported formats for each mode. Store all the infos in test resource.
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT AddTestResourceForConnector
+(
+ ResourceList& resourceList,
+ LPWSTR deviceId,
+ LPWSTR deviceName,
+ IMMDevice* pDevice,
+ EndpointConnectorType eConnectorType,
+ STACKWISE_DATAFLOW dataFlow
+)
+{
+ HRESULT hr = S_OK;
+ bool bHasConnector = false;
+ UINT uConnectorId;
+ ULONG cModes = 0;
+ CComHeapPtr<AUDIO_SIGNALPROCESSINGMODE> spModes;
+ AUDIO_SIGNALPROCESSINGMODE mode;
+ ULONG cFormatRecords = 0;
+ CComHeapPtr<FORMAT_RECORD> spFormatRecords;
+ wil::unique_cotaskmem_ptr<WAVEFORMATEX> pPreferredFormat;
+ UINT32 u32DefaultPeriodicityInFrames;
+ UINT32 u32FundamentalPeriodicityInFrames;
+ UINT32 u32MinPeriodicityInFrames;
+ UINT32 u32MaxPeriodicityInFrames;
+ UINT32 u32MaxPeriodicityInFramesExtended;
+ bool isAVStream = false;
+ bool isBluetooth = false;
+ bool isSideband = false;
+
+ // Get connector id
+ if (!VERIFY_SUCCEEDED(hr = GetConnectorId(pDevice, eConnectorType, &bHasConnector, &uConnectorId))) {
+ return hr;
+ }
+ if (!bHasConnector) {
+ return hr;
+ }
+
+ Log::Comment(String().Format(L"Adding Test Resource for pin [%u]:", (uConnectorId & PARTID_MASK)));
+
+
+ // Get all signal processing modes for connector
+ if (!VERIFY_SUCCEEDED(hr = GetProcessingModesForConnector(pDevice, uConnectorId, eConnectorType, &cModes, &spModes))) {
+ return hr;
+ }
+
+ // Loop through each mode, get preferred format and list of formats and create test resource for each mode
+ for (ULONG i = 0; i < cModes; i++) {
+
+ mode = spModes[i];
+
+ if (!VERIFY_SUCCEEDED(hr = GetSupportedFormatRecordsForConnector(pDevice, uConnectorId, eConnectorType, mode, dataFlow, &cFormatRecords, &spFormatRecords))) {
+ return hr;
+ }
+
+ if (!VERIFY_SUCCEEDED(hr = GetPreferredFormatForConnector(pDevice, uConnectorId, eConnectorType, mode, wil::out_param(pPreferredFormat)))) {
+ return hr;
+ }
+
+ if (!VERIFY_SUCCEEDED(hr = GetPreferredFormatPeriodicityCharacteristicsForConnector(pDevice, eConnectorType, mode, dataFlow, pPreferredFormat.get(), cFormatRecords, spFormatRecords, &u32DefaultPeriodicityInFrames, &u32FundamentalPeriodicityInFrames, &u32MinPeriodicityInFrames, &u32MaxPeriodicityInFrames, &u32MaxPeriodicityInFramesExtended))) {
+ return hr;
+ }
+
+ // Check if audio endpoint is AVStream
+ if (!VERIFY_SUCCEEDED(hr = IsAVStream(pDevice, &isAVStream))) {
+ return hr;
+ }
+
+ // Check if audio endpoint is Bluetooth
+ if (!VERIFY_SUCCEEDED(hr = IsBluetooth(pDevice, &isBluetooth))) {
+ return hr;
+ }
+
+ // Check if audio endpoint is side band
+ if (!VERIFY_SUCCEEDED(hr = IsSideband(pDevice, &isSideband))) {
+ return hr;
+ }
+
+ DeviceDescriptor descriptor = { 0 };
+ descriptor.pDevice = pDevice;
+ descriptor.pwstrAudioEndpointId = deviceId;
+ descriptor.pwstrAudioEndpointFriendlyName = deviceName;
+ descriptor.dataFlow = dataFlow;
+ descriptor.eConnectorType = eConnectorType;
+ descriptor.uConnectorId = uConnectorId;
+ descriptor.mode = mode;
+ descriptor.cModes = cModes;
+ descriptor.pModes = spModes;
+ descriptor.cFormatRecords = cFormatRecords;
+ descriptor.pFormatRecords = spFormatRecords;
+ descriptor.pPreferredFormat = pPreferredFormat.get();
+ descriptor.u32DefaultPeriodicityInFrames = u32DefaultPeriodicityInFrames;
+ descriptor.u32FundamentalPeriodicityInFrames = u32FundamentalPeriodicityInFrames;
+ descriptor.u32MinPeriodicityInFrames = u32MinPeriodicityInFrames;
+ descriptor.u32MaxPeriodicityInFrames = u32MaxPeriodicityInFrames;
+ descriptor.bIsAVStream = isAVStream;
+ descriptor.bIsBluetooth = isBluetooth;
+ descriptor.bIsSideband = isSideband;
+
+ if (!VERIFY_SUCCEEDED(hr = CreateTestResource(resourceList, descriptor))) {
+ return hr;
+ }
+
+ spFormatRecords.Free();
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// AddTestResourcesForDevice
+//
+// Identify the existence of all pin types and add test resources for each pin
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT AddTestResourcesForDevice
+(
+ ResourceList& resourceList,
+ LPWSTR deviceId,
+ LPWSTR deviceName,
+ STACKWISE_DATAFLOW dataFlow
+)
+{
+ HRESULT hr = S_OK;
+ wil::com_ptr_nothrow<IMMDeviceEnumerator> spEnumerator;
+ wil::com_ptr_nothrow<IMMDevice> spDevice;
+
+ Log::Comment(String().Format(L"Adding Test Resource for Device [%s]:", deviceName));
+
+ // Read the default device format from the property store
+ if (!VERIFY_SUCCEEDED(hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void **)&spEnumerator))) {
+ return hr;
+ }
+ if (!VERIFY_SUCCEEDED(hr = spEnumerator->GetDevice(deviceId, &spDevice))) {
+ return hr;
+ }
+
+ // Identify existence of host pin. Add test resources for host pin.
+ if (!VERIFY_SUCCEEDED(hr = AddTestResourceForConnector(resourceList, deviceId, deviceName, spDevice.get(), eHostProcessConnector, dataFlow))) {
+ return hr;
+ }
+
+ // Identify existence of offload pin. Add test resources for offload pin.
+ if (!VERIFY_SUCCEEDED(hr = AddTestResourceForConnector(resourceList, deviceId, deviceName, spDevice.get(), eOffloadConnector, dataFlow))) {
+ return hr;
+ }
+
+ // Identify existence of loopback pin. Add test resources for loopback pin.
+ if (!VERIFY_SUCCEEDED(hr = AddTestResourceForConnector(resourceList, deviceId, deviceName, spDevice.get(), eLoopbackConnector, capture ))) {
+ return hr;
+ }
+
+ /*
+ // Identify existence of keyword detector pin. Add test resources for keyword detector pin.
+ if (!VERIFY_SUCCEEDED(hr = AddTestResourceForConnector(resourceList, deviceId, deviceName, spDevice.get(), eKeywordDetectorConnector, dataFlow))) {
+ return hr;
+ }
+ */
+
+ return hr;
+}
+
+HRESULT __cdecl BuildResourceList(ResourceList& resourceList)
+{
+ HRESULT hr = S_OK;
+ wil::com_ptr_nothrow<IMMDeviceEnumerator> spEnumerator;
+ wil::com_ptr_nothrow<IMMDeviceCollection> spRenderEndpoints;
+ wil::com_ptr_nothrow<IMMDeviceCollection> spCaptureEndpoints;
+ wil::com_ptr_nothrow<IMMDevice> spEndpoint;
+ UINT cRenderDevices = 0;
+ UINT cCaptureDevices = 0;
+ UINT i = 0;
+ wil::unique_cotaskmem_string id;
+ wil::unique_cotaskmem_string friendlyName;
+
+ SetVerifyOutput verifySettings(VerifyOutputSettings::LogOnlyFailures);
+ DisableVerifyExceptions disable;
+
+ VERIFY_SUCCEEDED(::CoInitializeEx(NULL, COINIT_MULTITHREADED));
+
+ Log::Comment(L"In BuildResourceList");
+
+ // Create IMMDevice Enumerator
+ VERIFY_SUCCEEDED(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void **)&spEnumerator));
+
+ // Enumerate all render endpoints
+ VERIFY_SUCCEEDED(spEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &spRenderEndpoints));
+ VERIFY_SUCCEEDED(spRenderEndpoints->GetCount(&cRenderDevices));
+
+ // Enumerate all capture endpoints
+ VERIFY_SUCCEEDED(spEnumerator->EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE, &spCaptureEndpoints));
+ VERIFY_SUCCEEDED(spCaptureEndpoints->GetCount(&cCaptureDevices));
+
+ if (!VERIFY_IS_TRUE(cRenderDevices | cCaptureDevices))
+ {
+ hr = E_FAIL;
+ Log::Comment(L"No device was found!");
+ goto Exit;
+ }
+
+ Log::Comment(String().Format(L"Found %d viable rendering device!", cRenderDevices));
+ // Add test resources for render endpoints
+ if (cRenderDevices) {
+ for (i = 0; i < cRenderDevices; i++) {
+ VERIFY_SUCCEEDED(spRenderEndpoints->Item(i, &spEndpoint));
+ VERIFY_SUCCEEDED(spEndpoint->GetId(&id));
+ VERIFY_SUCCEEDED(GetEndpointFriendlyName(spEndpoint.get(), &friendlyName));
+
+ Log::Comment(String().Format(L"\\\\ Device: %s (%s)", friendlyName.get(), id.get()));
+ VERIFY_SUCCEEDED(AddTestResourcesForDevice(resourceList, id.get(), friendlyName.get(), render));
+ }
+ }
+
+ Log::Comment(String().Format(L"Found %d viable capture device!", cCaptureDevices));
+ // Add test resources for capture endpoints
+ if (cCaptureDevices) {
+ for (i = 0; i < cCaptureDevices; i++) {
+ VERIFY_SUCCEEDED(spCaptureEndpoints->Item(i, &spEndpoint));
+ VERIFY_SUCCEEDED(spEndpoint->GetId(&id));
+ VERIFY_SUCCEEDED(GetEndpointFriendlyName(spEndpoint.get(), &friendlyName));
+
+ Log::Comment(String().Format(L"\\\\ Device: %s (%s)", friendlyName.get(), id.get()));
+ VERIFY_SUCCEEDED(AddTestResourcesForDevice(resourceList, id.get(), friendlyName.get(), capture));
+ }
+ }
+
+ Log::Comment(L"Resource enumeration complete.");
+ Log::Comment(String().Format(L"Enumerated %u resources", resourceList.Count()));
+
+Exit:
+ return hr;
+}
diff --git a/audio/tests/KSPosTst/locallimits.h b/audio/tests/KSPosTst/locallimits.h
new file mode 100644
index 00000000..60336eb5
--- /dev/null
+++ b/audio/tests/KSPosTst/locallimits.h
@@ -0,0 +1,25 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// Module Name:
+//
+// locallimits.h
+//
+// Abstract:
+//
+// defines the tolerances for WHQL failures for this test app
+//
+// -------------------------------------------------------------------------------
+
+// max latency for rendering or capturing is 20 ms
+#define LATENCY_THRESHOLD 20.
+
+// Real time sampling rates must be within 1% of the theoretical rate,
+// per the format, as required by the PC98/PC99 HW Design Guide.
+#define SAMPLERATE_THRESHOLD 1.0
+
+// audio devices are required to be SAMPLEACCURATE (PC9x HW Design Guide)..
+// but for some reason we are making them ms accurate??
+#define JITTER_STD_THRESHOLD 1.0 // 1 ms max allowed for std-deviation
+#define JITTER_MAX_THRESHOLD 4.0 // 4 ms max allowed for max deviation
diff --git a/audio/tests/KSPosTst/pintest.cpp b/audio/tests/KSPosTst/pintest.cpp
new file mode 100644
index 00000000..57e35b07
--- /dev/null
+++ b/audio/tests/KSPosTst/pintest.cpp
@@ -0,0 +1,518 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// Module Name:
+//
+// pintest.cpp
+//
+// Abstract:
+//
+// Implementation file for test cases
+//
+// -------------------------------------------------------------------------------
+
+#include "PreComp.h"
+#include "KsPosTestTaef.h"
+#include "tests.h"
+
+#include <bestfit.h>
+#include <cmath>
+
+#define DEFAULT_PERIODICITY 0
+#define DEFAULT_LATENCY_COEFFICIENT 0
+#define xGetTime g_pKsPosTst->m_pTimer->Proc
+
+// ------------------------------------
+// Test_DriftAndJitter helper functions
+// ------------------------------------
+
+HRESULT CollectSampleData
+(
+ CHalfApp* pHalfApp,
+ PFORMAT_ENTRY pFormatEntry,
+ HNSTIME requestedPeriodicity
+)
+{
+ DWORD periodicityInMs = (DWORD)ceil(HNSTIME_TO_MILLISECONDS_DOUBLE(requestedPeriodicity));
+
+ if (!pFormatEntry)
+ {
+ ERR(g_pBasicLog, "FAIL: Current Format Entry is NULL.");
+ return E_INVALIDARG;
+ }
+
+ PPERF_RESULTS pResults = &pFormatEntry->perfResults;
+ PPOSITION_SET pPosSet = pResults->argPosSets;
+ double tStart = 0, tPre = 0, tPost = 0;
+ UINT i = 0;
+ UINT64 u64Position;
+ UINT64 positionHNS;
+ UINT64 u64Frequency;
+ double testStartHns;
+ LARGE_INTEGER liNow;
+ LARGE_INTEGER liFrequency;
+ QueryPerformanceFrequency(&liFrequency);
+
+ VERIFY_SUCCEEDED(pHalfApp->InitializeEndpoint());
+ VERIFY_SUCCEEDED(pHalfApp->CreateSineToneDataBuffer(pHalfApp->m_pCurrentFormat.get()));
+ VERIFY_SUCCEEDED(pHalfApp->InitializeStream(requestedPeriodicity, DEFAULT_LATENCY_COEFFICIENT));
+
+ // run the adapter sink pin
+ VERIFY_SUCCEEDED(pHalfApp->StartStream());
+
+ // Get a HNS reference from the begining of the test so the HNS from system and driver times won't be so large
+ QueryPerformanceCounter(&liNow);
+ testStartHns = (double)liNow.QuadPart * HNSTIME_UNITS_PER_SECOND / (double)liFrequency.QuadPart;
+
+ tStart = xGetTime();
+ Sleep(DELAY_FOR_STABILIZE);
+ // Get the stream frequency in order to determine the time offset
+ VERIFY_SUCCEEDED(pHalfApp->m_pAudioClock->GetFrequency(&u64Frequency));
+
+ // Start collecting the data
+ for (i = 0; i < DATA_POINTS;)
+ {
+ Sleep(periodicityInMs);
+
+ tPre = xGetTime();
+ VERIFY_SUCCEEDED(pHalfApp->GetPosition(&u64Position, &positionHNS));
+ QueryPerformanceCounter(&liNow);
+ tPost = xGetTime();
+
+ if (u64Position > 0)
+ {
+ // only count this result if the GetPosition and GetTime happened relatively atomically
+ if ((tPost - tPre) < 1.)
+ {
+ double testHNS = (double)liNow.QuadPart * HNSTIME_UNITS_PER_SECOND / (double)liFrequency.QuadPart;
+ // In both sampling rate and jitter calculation, the time used is in milliseconds, so we can convert it right here
+ pPosSet[i].testTime = HNSTIME_TO_MILLISECONDS_DOUBLE(testHNS - testStartHns);
+ pPosSet[i].positionTime = HNSTIME_TO_MILLISECONDS_DOUBLE(positionHNS - testStartHns);
+ // We store the values as seconds because it is easier to convert to bytes per second, on sampling rate calculation, and milliseconds, on jitter calculation.
+ pPosSet[i].position = (double)u64Position / (double)u64Frequency;
+
+ // Ignore repeated positions (that means they have the same QPC and should have the same position value)
+ if ((i > 0) && (pPosSet[i - 1].positionTime == pPosSet[i].positionTime))
+ {
+ // If the position is the same, decrement the count so that sample gets discarded by overwriting it
+ i--;
+ WARN(g_pBasicLog, "The same position was reported at %f ms: pos = %f seconds", pPosSet[i].testTime, pPosSet[i].position);
+ }
+ i++;
+ }
+ else
+ {
+ LOG(g_pBasicLog, "GetPosition function too slow");
+ }
+ }
+ // If a non-zero position has not been reported during one second, break the loop and check if there is enough data
+ else if ((tPost - tStart) > MILLISECONDS_PER_SECOND)
+ {
+ break;
+ }
+
+ pResults->cPosSets = i;
+ }
+
+ VERIFY_SUCCEEDED(pHalfApp->StopStream());
+
+ // Did we get enough data?
+ VERIFY_IS_TRUE(pResults->cPosSets >= 30);
+
+ return S_OK;
+}
+
+// --------------------------------------------------------------------------------------------------
+// CalculateSampleRate
+// --------------------------------------------------------------------------------------------------
+HRESULT CalculateSampleRate
+(
+ PFORMAT_ENTRY pFormatEntry
+)
+{
+ WAVEFORMATEX* pwfx = &pFormatEntry->wfxFormat.Format;
+ PPERF_RESULTS pResults = &pFormatEntry->perfResults;
+
+ double dError, dErrorPercent;
+
+ // Pair the positions with test HNS time to find the slope
+ // Alocate memory for this type-specific array
+ wil::unique_cotaskmem_ptr<DPOINT> pointArray((PDPOINT)CoTaskMemAlloc(DATA_POINTS * sizeof(DPOINT)));
+ PDPOINT pArray = pointArray.get();
+ // Get a pointer to the sample set
+ PPOSITION_SET posSet = pResults->argPosSets;
+ for (int i = 0; i < DATA_POINTS; i++)
+ {
+ pArray[i].x = posSet[i].positionTime;
+ pArray[i].y = posSet[i].position * pwfx->nAvgBytesPerSec; // Convert to bytes
+ }
+
+ ULONG cArray = pResults->cPosSets; // number of points
+
+ // calculate the slope and intercept (bytes per second and latency)
+ pResults->bytesPerSecond = SLOPE(pArray, cArray);
+ pResults->dOffset = INTERCEPT(pArray, cArray, pResults->bytesPerSecond);
+
+ // Convert from bytes/ms to bytes/sec
+ pResults->bytesPerSecond *= MILLISECONDS_PER_SECOND;
+
+ // The offset is used in the jitter calculation and it is used in milliseconds, so we can save it in those units
+ pResults->dOffset = pResults->dOffset / pResults->bytesPerSecond * MILLISECONDS_PER_SECOND;
+
+ // calculate errors
+ dError = pResults->bytesPerSecond - (double)pwfx->nAvgBytesPerSec;
+ dErrorPercent = (dError / (double)pwfx->nAvgBytesPerSec) * 100.0;
+
+ if (g_pKsPosTst->m_fLogHistograms)
+ {
+ LOG(g_pBasicLog, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
+ LOG(g_pBasicLog, "SampleRate calculated from histogram (method of least squares)\n");
+
+ LOG(g_pBasicLog, "Collected %d data points", pResults->cPosSets);
+ LOG(g_pBasicLog, "Specified sample rate = %6.3f bytes/sec, %6.3f samples/sec", (double)(pwfx->nBlockAlign * pwfx->nSamplesPerSec), (double)pwfx->nSamplesPerSec);
+ LOG(g_pBasicLog, "Calculated sample rate = %6.3f bytes/sec, %6.3f samples/sec", pResults->bytesPerSecond, pResults->bytesPerSecond / (double)pwfx->nBlockAlign);
+ LOG(g_pBasicLog, "Error = %.3f %%", dErrorPercent);
+ LOG(g_pBasicLog, "Calculated time offset = %f ms", pResults->dOffset);
+ }
+
+ // evaluate the results
+ VERIFY_IS_TRUE(abs(dErrorPercent) <= SAMPLERATE_THRESHOLD);
+
+ return S_OK;
+}
+
+// --------------------------------------------------------------------------------------------------
+// CalculateJitter
+// --------------------------------------------------------------------------------------------------
+HRESULT CalculateJitter
+(
+ PFORMAT_ENTRY pFormatEntry
+)
+{
+ PPERF_RESULTS pResults = &pFormatEntry->perfResults;
+
+ double dError = 0.0;
+ double dErrorAve = 0.0;
+ double dErrorMax = 0.0;
+ double dStdDeviation = 0.0;
+ double reportedPosition;
+ double timeDifference;
+ ULONG i;
+ PPOSITION_SET pPosSet = pResults->argPosSets;
+
+ if (g_pKsPosTst->m_fLogHistograms)
+ {
+ LOG(g_pBasicLog, "Reported QPC Compensated Expected");
+ LOG(g_pBasicLog, "position adjust position position Error");
+ LOG(g_pBasicLog, "(ms) (ms) (ms) (ms) (ms)");
+ LOG(g_pBasicLog, "========== ========== ========== ========== ==========");
+ }
+
+ for (i = 0; i < pResults->cPosSets; i++)
+ {
+ // Convert the time offset from seconds to milliseconds
+ reportedPosition = pPosSet[i].position * MILLISECONDS_PER_SECOND; // milliseconds
+
+ // First, we compensate for the latency of the samples (they were taken 100 ms after stream start)
+ pPosSet[i].position = reportedPosition - pResults->dOffset; // The offset is already in ms
+
+ // Then, before comparing the expected and actual position, adjust the given sample to get the position corresponding to the test time.
+ timeDifference = pPosSet[i].testTime - pPosSet[i].positionTime; // milliseconds
+ // If the difference is positive, the time of the position is behind of what is expected and that position gets increased accordingly.
+ // If the difference is negative, the time of the position is ahead of what is expected and that position gets decreased accordingly.
+ // In the rare case when the QPC and time are the same, the difference is zero because we are on the spot and that is the position that should be compared.
+ pPosSet[i].position += timeDifference; // milliseconds
+
+ dError = pPosSet[i].testTime - pPosSet[i].position;
+ dErrorAve += dError;
+
+ if (g_pKsPosTst->m_fLogHistograms)
+ {
+ LOG(g_pBasicLog, "%10.2f, %10.2f, %10.2f, %10.2f, %10.2f", reportedPosition, timeDifference, pPosSet[i].position, pPosSet[i].testTime, dError);
+ }
+
+ if (dError < 0.)
+ dError = -dError;
+ if (dError > dErrorMax)
+ dErrorMax = dError;
+ }
+
+ dErrorAve /= (double)pResults->cPosSets;
+
+ VERIFY_IS_TRUE((ULONG)dErrorAve < 2); // if this is not true then, there's something wrong with our compensation...
+
+ for (i = 0; i < pResults->cPosSets; i++)
+ {
+ dError = pPosSet[i].testTime - pPosSet[i].position;
+ dStdDeviation += ((dError - dErrorAve) * (dError - dErrorAve));
+ }
+
+ dStdDeviation /= (double)pResults->cPosSets;
+ dStdDeviation = sqrt(dStdDeviation);
+
+ if (g_pKsPosTst->m_fLogHistograms)
+ {
+ LOG(g_pBasicLog, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
+ LOG(g_pBasicLog, "Jitter calculated from histogram (with (samplerate drift and latency) compensation)\n");
+ LOG(g_pBasicLog, "Max deviation = %6.3f ms", dErrorMax);
+ LOG(g_pBasicLog, "Standard deviation = %6.3f ms", dStdDeviation);
+ }
+
+ // evaluate the results ~~~~~~~~~~~~~
+ VERIFY_IS_TRUE(abs(dErrorMax) < JITTER_MAX_THRESHOLD);
+ VERIFY_IS_TRUE(abs(dStdDeviation) < JITTER_STD_THRESHOLD);
+
+ return S_OK;
+}
+
+// ------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------
+void Test_DriftAndJitter_Main
+(
+ HNSTIME requestedPeriodicity
+)
+{
+ CHalfApp* pHalfApp = g_pKsPosTst->m_pHalf;
+ CHalfApp* pHostHalfApp = g_pKsPosTst->m_pHostHalf;
+ BOOL isLoopbackPin = pHalfApp->m_ConnectorType == eLoopbackConnector;
+
+ // Test will ignore Bluetooth devices until proper thresholds are in place.
+ if (pHalfApp->m_bIsBluetooth)
+ {
+ SKIP(g_pBasicLog, "Test is not supported for Bluetooth pins");
+ return;
+ }
+
+ // If this is a loobpack pin, start the host pin's stream
+ // This can be done before collecting the samples, since the host pin will keep playing until stopped
+ if (isLoopbackPin)
+ {
+ // Match loopback stream format with host stream format
+ CloneWaveFormat(pHostHalfApp->m_pCurrentFormat.get(), wil::out_param(pHalfApp->m_pCurrentFormat));
+ pHalfApp->m_u32CurrentDefaultPeriodicityInFrames = pHostHalfApp->m_u32CurrentDefaultPeriodicityInFrames;
+ pHalfApp->m_u32CurrentFundamentalPeriodicityInFrames = pHostHalfApp->m_u32CurrentFundamentalPeriodicityInFrames;
+ pHalfApp->m_u32CurrentMinPeriodicityInFrames = pHostHalfApp->m_u32CurrentMinPeriodicityInFrames;
+ pHalfApp->m_u32CurrentMaxPeriodicityInFrames = pHostHalfApp->m_u32CurrentMaxPeriodicityInFrames;
+
+ // Initialize and start host stream
+ VERIFY_SUCCEEDED(pHostHalfApp->InitializeEndpoint());
+ VERIFY_SUCCEEDED(pHostHalfApp->CreateSineToneDataBuffer(pHostHalfApp->m_pCurrentFormat.get()));
+ VERIFY_SUCCEEDED(pHostHalfApp->InitializeStream(requestedPeriodicity, DEFAULT_LATENCY_COEFFICIENT));
+ VERIFY_SUCCEEDED(pHostHalfApp->StartStream());
+ }
+
+ FORMAT_ENTRY results;
+ memset(&results, 0, sizeof(FORMAT_ENTRY));
+ results.wfxFormat.Format = *pHalfApp->m_pCurrentFormat.get();
+ // Alocate memory for the sample data
+ wil::unique_cotaskmem_ptr<POSITION_SET> pPositionSet((PPOSITION_SET)CoTaskMemAlloc(DATA_POINTS * sizeof(POSITION_SET)));
+ results.perfResults.argPosSets = pPositionSet.get();
+
+ // collect the data ~~~~~~~~~~~~~~~~~
+ VERIFY_SUCCEEDED(CollectSampleData(pHalfApp, &results, requestedPeriodicity));
+
+ // Stop and cleanup the host stream since we are done collecting samples
+ if (isLoopbackPin)
+ {
+ VERIFY_SUCCEEDED(pHostHalfApp->StopStream());
+ VERIFY_SUCCEEDED(pHostHalfApp->CleanupStream());
+ VERIFY_SUCCEEDED(pHostHalfApp->ReleaseEndpoint());
+ VERIFY_SUCCEEDED(pHostHalfApp->ReleaseSineToneDataBuffer());
+ }
+
+ // calculate drift ~~~~~~~~~~~~~~~~~~
+ VERIFY_SUCCEEDED(CalculateSampleRate(&results));
+
+ // calculate Jitter ~~~~~~~~~~~~~~~~~
+ VERIFY_SUCCEEDED(CalculateJitter(&results));
+}
+
+// ------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------
+void Test_DriftAndJitter_Default(void)
+{
+ HNSTIME requestedTime = FRAMES_TO_HNSTIME_DOUBLE(g_pKsPosTst->m_pHalf->m_u32CurrentDefaultPeriodicityInFrames, g_pKsPosTst->m_pHalf->m_pCurrentFormat->nSamplesPerSec);
+ if (g_pKsPosTst->m_fLogHistograms)
+ {
+ LOG(g_pBasicLog, "Periodicity: %d frames, %f ms", g_pKsPosTst->m_pHalf->m_u32CurrentDefaultPeriodicityInFrames, HNSTIME_TO_MILLISECONDS_DOUBLE(requestedTime));
+ }
+ Test_DriftAndJitter_Main(requestedTime);
+}
+
+/*
+ Perform a cycle of creating a pin, starting a stream, stoping and destroying.
+
+ This is done with the idea of putting the driver and audio hardware in an active state
+ before doing time sensitive tests.
+*/
+void ActivateDriver(CHalfApp* pHalfApp)
+{
+ VERIFY_SUCCEEDED(pHalfApp->InitializeEndpoint());
+ VERIFY_SUCCEEDED(pHalfApp->CreateSineToneDataBuffer(pHalfApp->m_pCurrentFormat.get()));
+ VERIFY_SUCCEEDED(pHalfApp->InitializeStream(DEFAULT_PERIODICITY, DEFAULT_LATENCY_COEFFICIENT));
+ VERIFY_SUCCEEDED(pHalfApp->StartStream());
+ Sleep(100);
+ VERIFY_SUCCEEDED(pHalfApp->StopStream());
+ VERIFY_SUCCEEDED(pHalfApp->CleanupStream());
+ VERIFY_SUCCEEDED(pHalfApp->ReleaseEndpoint());
+ VERIFY_SUCCEEDED(pHalfApp->ReleaseSineToneDataBuffer());
+}
+
+// ------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------
+void Test_Latency_Main (HNSTIME requestedPeriodicity)
+{
+ CHalfApp* pHalfApp = g_pKsPosTst->m_pHalf;
+ CHalfApp* pHostHalfApp = g_pKsPosTst->m_pHostHalf;
+ NTSTATUS lTimerResStatus;
+ BOOL isLoopbackPin = pHalfApp->m_ConnectorType == eLoopbackConnector;
+
+ // Test will ignore Bluetooth devices until proper thresholds are in place.
+ if (pHalfApp->m_bIsBluetooth)
+ {
+ SKIP(g_pBasicLog, "Test is not supported for Bluetooth pins");
+ return;
+ }
+
+ lTimerResStatus = NtSetTimerResolution(timerResolution, TRUE, &actualTimerResolution);
+
+ if (!NT_SUCCESS(lTimerResStatus))
+ {
+ SKIP(g_pBasicLog, "Fail to set timer precision. Skip the test.");
+ return;
+ }
+
+ // If it is a loopback pin, get the host pin and start the stream
+ if (isLoopbackPin)
+ {
+ // Match loopback stream format with host stream format
+ CloneWaveFormat(pHostHalfApp->m_pCurrentFormat.get(), wil::out_param(pHalfApp->m_pCurrentFormat));
+ pHalfApp->m_u32CurrentDefaultPeriodicityInFrames = pHostHalfApp->m_u32CurrentDefaultPeriodicityInFrames;
+ pHalfApp->m_u32CurrentFundamentalPeriodicityInFrames = pHostHalfApp->m_u32CurrentFundamentalPeriodicityInFrames;
+ pHalfApp->m_u32CurrentMinPeriodicityInFrames = pHostHalfApp->m_u32CurrentMinPeriodicityInFrames;
+ pHalfApp->m_u32CurrentMaxPeriodicityInFrames = pHostHalfApp->m_u32CurrentMaxPeriodicityInFrames;
+
+ // Initialize and start host stream
+ VERIFY_SUCCEEDED(pHostHalfApp->InitializeEndpoint());
+ VERIFY_SUCCEEDED(pHostHalfApp->CreateSineToneDataBuffer(pHostHalfApp->m_pCurrentFormat.get()));
+ VERIFY_SUCCEEDED(pHostHalfApp->InitializeStream(requestedPeriodicity, DEFAULT_LATENCY_COEFFICIENT));
+ VERIFY_SUCCEEDED(pHostHalfApp->StartStream());
+ }
+
+ // Perform a stream cycle to make sure the driver is on a good state
+ ActivateDriver(pHalfApp);
+
+ // Initialize the stream
+ VERIFY_SUCCEEDED(pHalfApp->InitializeEndpoint());
+ VERIFY_SUCCEEDED(pHalfApp->CreateSineToneDataBuffer(pHalfApp->m_pCurrentFormat.get()));
+ VERIFY_SUCCEEDED(pHalfApp->InitializeStream(requestedPeriodicity, DEFAULT_LATENCY_COEFFICIENT));
+
+ UINT64 u64Position = 0;
+ UINT64 driverHns = 0;
+
+ double tPosPre = 0.0;
+ double tPosPost = 0.0;
+
+ LARGE_INTEGER liFrequency = { 0 };
+ LARGE_INTEGER timeStamp = { 0 };
+ QueryPerformanceFrequency(&liFrequency);
+
+ // mark the time
+ double tRunPre = xGetTime();
+ // Start the stream
+ VERIFY_SUCCEEDED(pHalfApp->StartStream());
+ // mark the time
+ double tRunPost = xGetTime();
+
+ LOG(g_pBasicLog, "Starting the stream took %.03f ms", (tRunPost - tRunPre));
+
+ // loop until we get a non-zero position
+ while (u64Position == 0)
+ {
+ Sleep(1);
+ // timer before position call
+ tPosPre = xGetTime();
+ VERIFY_SUCCEEDED(pHalfApp->GetPosition(&u64Position, &driverHns));
+ QueryPerformanceCounter(&timeStamp);
+ // timer after position call
+ tPosPost = xGetTime();
+ if (g_pKsPosTst->m_fLogHistograms)
+ {
+ LOG(g_pBasicLog, "Testing first non-zero position reported: %u samples, %u HNS at %.03f ms", u64Position, driverHns, tPosPost - tRunPre);
+ }
+
+ // Fail if the cursor does not move within 500 ms
+ VERIFY_IS_TRUE((tPosPost - tRunPost) < 500.0);
+ }
+
+ // Before stopping, get the frequency of the stream
+ UINT64 u64Frequency;
+ VERIFY_SUCCEEDED(pHalfApp->m_pAudioClock->GetFrequency(&u64Frequency));
+
+ // the uncertainty in time is the max possible value minus the min possible value divided by 2 (for +/- purposes)
+ double tMax = tPosPost - tRunPre;
+ double tMin = tPosPre - tRunPost;
+ double tAve = (tMax + tMin) / 2.0;
+ double tUncertainty = (tMax - tMin) / 2.0;
+
+ // Convert the stream position to an offset of milliseconds
+ double tOffset = MILLISECONDS_PER_SECOND * (double)u64Position / (double)u64Frequency;
+
+ // Calculate the difference in time of the position time versus the test time
+ UINT64 testHns = 10000000 * timeStamp.QuadPart / liFrequency.QuadPart;
+ INT64 timeDiff = testHns - driverHns;
+
+ // Compensate the positon to take this difference into account
+ tOffset += (double)timeDiff / HNSTIME_UNITS_PER_MILLISECOND;
+
+ if (g_pKsPosTst->m_fLogHistograms)
+ {
+ LOG(g_pBasicLog, "Times (HNS): %u, %u", testHns, driverHns);
+ LOG(g_pBasicLog, "Time difference: %d HNS (%f ms)", timeDiff, (double)timeDiff / HNSTIME_UNITS_PER_MILLISECOND);
+ LOG(g_pBasicLog, "First non-zero position = %u at %g ms", u64Position, tAve);
+ LOG(g_pBasicLog, "Time offset / max time: %f ms / %f ms", tOffset, tMax);
+ LOG(g_pBasicLog, "Frequency: %lu", u64Frequency);
+ }
+
+ double tLatency;
+ tLatency = tAve - tOffset;
+ if (tLatency < 0)
+ {
+ // This means that the position is between the average and max times, which should be OK (as long as it is not above the max)
+ tLatency *= -1;
+ LOG(g_pBasicLog, "The position is greater than the average time");
+ }
+ LOG(g_pBasicLog, "Adjusted latency = %.03f ms (+/- %.3f ms)", tLatency, tUncertainty);
+
+ // if the reported position is outside the max time for this call (see tUncertainty calculation above), then fail
+ // temp fix until we know how far can be the data in front of the
+ // real time because of buffering
+ VERIFY_IS_FALSE(tOffset > tMax);
+
+ // Verify that the latency is within the threshold
+ VERIFY_IS_TRUE(tLatency <= LATENCY_THRESHOLD); // ms
+
+ // Stop the endpoint
+ VERIFY_SUCCEEDED(pHalfApp->StopStream());
+ // If this was a loopback pin, stop the host stream also
+ if (isLoopbackPin)
+ {
+ VERIFY_SUCCEEDED(pHostHalfApp->StopStream());
+ VERIFY_SUCCEEDED(pHostHalfApp->CleanupStream());
+ VERIFY_SUCCEEDED(pHostHalfApp->ReleaseEndpoint());
+ VERIFY_SUCCEEDED(pHostHalfApp->ReleaseSineToneDataBuffer());
+ }
+
+ // Turn off the higher resolution timer
+ NtSetTimerResolution(0, FALSE, &actualTimerResolution);
+}
+
+// ------------------------------------------------------------------------------
+// ------------------------------------------------------------------------------
+void Test_Latency_Default(void)
+{
+ HNSTIME requestedTime = FRAMES_TO_HNSTIME_DOUBLE(g_pKsPosTst->m_pHalf->m_u32CurrentDefaultPeriodicityInFrames, g_pKsPosTst->m_pHalf->m_pCurrentFormat->nSamplesPerSec);
+ LOG(g_pBasicLog, "Periodicity: %d frames, %f ms", g_pKsPosTst->m_pHalf->m_u32CurrentDefaultPeriodicityInFrames, HNSTIME_TO_MILLISECONDS_DOUBLE(requestedTime));
+ Test_Latency_Main(requestedTime);
+}
diff --git a/audio/tests/KSPosTst/tests.h b/audio/tests/KSPosTst/tests.h
new file mode 100644
index 00000000..ec0a68cc
--- /dev/null
+++ b/audio/tests/KSPosTst/tests.h
@@ -0,0 +1,18 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// Module Name:
+//
+// tests.h
+//
+// Abstract:
+//
+// Header for testcases
+//
+// -------------------------------------------------------------------------------
+#pragma once
+
+void Test_DriftAndJitter_Default(void);
+
+void Test_Latency_Default(void);
diff --git a/audio/tests/KSPosTst/timetest.cpp b/audio/tests/KSPosTst/timetest.cpp
new file mode 100644
index 00000000..d8026716
--- /dev/null
+++ b/audio/tests/KSPosTst/timetest.cpp
@@ -0,0 +1,50 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+// Module Name:
+//
+// timetest.cpp
+//
+// Abstract:
+//
+// Functions to precisely measure time.
+//
+// -------------------------------------------------------------------------------
+
+#include "PreComp.h"
+#include <math.h>
+
+// ------------------------------------------------------------------------------
+// returns millisecs
+double tpQPC (void)
+{
+ static LARGE_INTEGER liFrequency = { 0 };
+ static LARGE_INTEGER liStart = { 0 };
+ static bool bInitialized = false;
+
+ if (!bInitialized)
+ {
+ if (!QueryPerformanceFrequency(&liFrequency))
+ {
+ throw ("QueryPerformanceFrequency failed");
+ }
+
+ if (!QueryPerformanceCounter(&liStart))
+ {
+ throw ("QueryPerformanceCounter failed");
+ }
+
+ bInitialized = true;
+ }
+
+ LARGE_INTEGER liNow = { 0 };
+
+ if (!QueryPerformanceCounter(&liNow))
+ {
+ throw ("QueryPerformanceCounter failed");
+ }
+
+ // milliseconds since test start
+ return 1000.0 * (liNow.QuadPart - liStart.QuadPart) / liFrequency.QuadPart;
+}
diff --git a/audio/tests/wavetest/HalfApp.cpp b/audio/tests/PinResourceHelpers/HalfApp.cpp
index 14a15c08..83c9c8f3 100644
--- a/audio/tests/wavetest/HalfApp.cpp
+++ b/audio/tests/PinResourceHelpers/HalfApp.cpp
@@ -12,15 +12,16 @@
//
// -------------------------------------------------------------------------------
-#include "PreComp.h"
-#include "WaveTestTaef.h"
-#include "HalfApp.h"
-#include "TestResourceHelper.h"
-#include "PropertyHelper.h"
-#include <dithering.h>
-#include <signal-source.h>
-#include <sine-signal-source.h>
-#include <dvmodule.h>
+
+
+
+
+
+
+
+
+
+
HRESULT
CHalfApp::InitializeEndpoint
@@ -114,6 +115,9 @@ CHalfApp::InitializeEndpoint
if (!VERIFY_SUCCEEDED(hr = m_pAudioDeviceEndpoint.query_to(&m_pAudioEndpointRT))) {
return hr;
}
+ if (!VERIFY_SUCCEEDED(hr = m_pAudioDeviceEndpoint.query_to(&m_pAudioClock))) {
+ return hr;
+ }
return hr;
}
@@ -134,6 +138,7 @@ CHalfApp::ReleaseEndpoint
m_pAudioEndpointControl.reset();
m_pAudioEndpoint.reset();
m_pAudioEndpointRT.reset();
+ m_pAudioClock.reset();
return hr;
}
@@ -380,6 +385,7 @@ CHalfApp::GetSecondHalfApp
UINT32 u32MinPeriodicityInFrames;
UINT32 u32MaxPeriodicityInFrames;
UINT32 u32MaxPeriodicityInFramesExtended;
+ DeviceDescriptor descriptor = { 0 };
if (!VERIFY_SUCCEEDED(hr = GetSupportedFormatRecordsForConnector(m_pDevice.get(), m_uConnectorId, m_ConnectorType, secondMode, m_DataFlow, &cFormatRecords, &spFormatRecords))) {
return hr;
@@ -393,7 +399,26 @@ CHalfApp::GetSecondHalfApp
return hr;
}
- *ppSecondHalfApp = new CHalfApp(m_pDevice.get(), m_pwstrDeviceId.get(), m_pwstrDeviceFriendlyName.get(), m_DataFlow, m_ConnectorType, m_uConnectorId, secondMode, m_cModes, m_pModes, cFormatRecords, spFormatRecords, pPreferredFormat.get(), u32DefaultPeriodicityInFrames, u32FundamentalPeriodicityInFrames, u32MinPeriodicityInFrames, u32MaxPeriodicityInFrames);
+ descriptor.pDevice = m_pDevice.get();
+ descriptor.pwstrAudioEndpointId = m_pwstrDeviceId.get();
+ descriptor.pwstrAudioEndpointFriendlyName = m_pwstrDeviceFriendlyName.get();
+ descriptor.dataFlow = m_DataFlow;
+ descriptor.eConnectorType = m_ConnectorType;
+ descriptor.uConnectorId = m_uConnectorId;
+ descriptor.mode = secondMode;
+ descriptor.cModes = m_cModes;
+ descriptor.pModes = m_pModes;
+ descriptor.cFormatRecords = cFormatRecords;
+ descriptor.pFormatRecords = spFormatRecords;
+ descriptor.pPreferredFormat = pPreferredFormat.get();
+ descriptor.u32DefaultPeriodicityInFrames = u32DefaultPeriodicityInFrames;
+ descriptor.u32FundamentalPeriodicityInFrames = u32FundamentalPeriodicityInFrames;
+ descriptor.u32MinPeriodicityInFrames = u32MinPeriodicityInFrames;
+ descriptor.u32MaxPeriodicityInFrames = u32MaxPeriodicityInFrames;
+ descriptor.bIsAVStream = m_bIsAVStream;
+ descriptor.bIsBluetooth = m_bIsBluetooth;
+ descriptor.bIsSideband = m_bIsSideband;
+ *ppSecondHalfApp = new CHalfApp(descriptor);
if (*ppSecondHalfApp == NULL) {
hr = E_OUTOFMEMORY;
return hr;
@@ -432,6 +457,7 @@ CHalfApp::GetHostHalfApp
UINT32 u32MinPeriodicityInFrames;
UINT32 u32MaxPeriodicityInFrames;
UINT32 u32MaxPeriodicityInFramesExtended;
+ DeviceDescriptor descriptor = { 0 };
// It is only used when testing on loopback pin. When preparing loopback pin, we also need prepare the host pin.
VERIFY_IS_TRUE(m_ConnectorType == eLoopbackConnector);
@@ -474,7 +500,26 @@ CHalfApp::GetHostHalfApp
return hr;
}
- *ppHostHalfApp = new CHalfApp(m_pDevice.get(), m_pwstrDeviceId.get(), m_pwstrDeviceFriendlyName.get(), render, eHostProcessConnector, uConnectorId, mode, cModes, spModes, cFormatRecords, spFormatRecords, pPreferredFormat.get(), u32DefaultPeriodicityInFrames, u32FundamentalPeriodicityInFrames, u32MinPeriodicityInFrames, u32MaxPeriodicityInFrames);
+ descriptor.pDevice = m_pDevice.get();
+ descriptor.pwstrAudioEndpointId = m_pwstrDeviceId.get();
+ descriptor.pwstrAudioEndpointFriendlyName = m_pwstrDeviceFriendlyName.get();
+ descriptor.dataFlow = render;
+ descriptor.eConnectorType = eHostProcessConnector;
+ descriptor.uConnectorId = uConnectorId;
+ descriptor.mode = mode;
+ descriptor.cModes = cModes;
+ descriptor.pModes = spModes;
+ descriptor.cFormatRecords = cFormatRecords;
+ descriptor.pFormatRecords = spFormatRecords;
+ descriptor.pPreferredFormat = pPreferredFormat.get();
+ descriptor.u32DefaultPeriodicityInFrames = u32DefaultPeriodicityInFrames;
+ descriptor.u32FundamentalPeriodicityInFrames = u32FundamentalPeriodicityInFrames;
+ descriptor.u32MinPeriodicityInFrames = u32MinPeriodicityInFrames;
+ descriptor.u32MaxPeriodicityInFrames = u32MaxPeriodicityInFrames;
+ descriptor.bIsAVStream = m_bIsAVStream;
+ descriptor.bIsBluetooth = m_bIsBluetooth;
+ descriptor.bIsSideband = m_bIsSideband;
+ *ppHostHalfApp = new CHalfApp(descriptor);
if (*ppHostHalfApp == NULL) {
hr = E_OUTOFMEMORY;
return hr;
@@ -987,13 +1032,9 @@ inline void CHalfApp::CancelTimer(HANDLE timer)
HRESULT CHalfApp::GetPosition(UINT64* pu64Position, UINT64* pu64hnsQPCPosition)
{
HRESULT hr = S_OK;
- wil::com_ptr_nothrow<IAudioClock> spAudioClock;
auto lock = m_CritSec.lock();
- if (!VERIFY_SUCCEEDED(m_pAudioDeviceEndpoint.query_to(&spAudioClock))) {
- return hr;
- }
- if (!VERIFY_SUCCEEDED(spAudioClock->GetPosition(pu64Position, pu64hnsQPCPosition))) {
+ if (!VERIFY_SUCCEEDED(m_pAudioClock->GetPosition(pu64Position, pu64hnsQPCPosition))) {
return hr;
}
diff --git a/audio/tests/PinResourceHelpers/PreComp.h b/audio/tests/PinResourceHelpers/PreComp.h
new file mode 100644
index 00000000..85fc4f83
--- /dev/null
+++ b/audio/tests/PinResourceHelpers/PreComp.h
@@ -0,0 +1,143 @@
+// ------------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+// File Name:
+//
+// PreComp.h
+//
+// Abstract:
+//
+// Precompiled common headers
+//
+// -------------------------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// Define custom test resource properties
+namespace WEX {
+ namespace TestExecution {
+ namespace TestResourceProperty
+ {
+ static const wchar_t c_szMode[] = L"Mode";
+ static const wchar_t c_szPin[] = L"Pin";
+ }
+ }
+}
+
+// ----------------------------------------------------------
+// Parameters for test sine tone
+#define TEST_AMPLITUDE 1.0f
+#define TEST_FREQUENCY 200.0f
+
+// ----------------------------------------------------------
+// Predefined format list for offload streaming
+#define COUNT_FORMATS 4
+
+static WAVEFORMATEXTENSIBLE ListofFormats[COUNT_FORMATS] =
+{
+ // 1
+ {
+ // Format
+ {
+ WAVE_FORMAT_EXTENSIBLE, // wFormatTag
+ 2, // nChannels
+ 44100, // nSamplesPerSec
+ 176400, // nAvgBytesPerSec
+ 4, // nBlockAlign
+ 16, // wBitsPerSample
+ 22 // cbSize
+ },
+ // Samples
+ {
+ 16 // wValidBitsPerSample
+ },
+ KSAUDIO_SPEAKER_STEREO, // dwChannelMask
+ KSDATAFORMAT_SUBTYPE_PCM // SubFormat
+ },
+ // 2
+ {
+ // Format
+ {
+ WAVE_FORMAT_EXTENSIBLE, // wFormatTag
+ 2, // nChannels
+ 48000, // nSamplesPerSec
+ 192000, // nAvgBytesPerSec
+ 4, // nBlockAlign
+ 16, // wBitsPerSample
+ 22 // cbSize
+ },
+ // Samples
+ {
+ 16 // wValidBitsPerSample
+ },
+ KSAUDIO_SPEAKER_STEREO, // dwChannelMask
+ KSDATAFORMAT_SUBTYPE_PCM // SubFormat
+ },
+ // 3
+ {
+ // Format
+ {
+ WAVE_FORMAT_EXTENSIBLE, // wFormatTag
+ 2, // nChannels
+ 88200, // nSamplesPerSec
+ 352800, // nAvgBytesPerSec
+ 4, // nBlockAlign
+ 16, // wBitsPerSample
+ 22 // cbSize
+ },
+ // Samples
+ {
+ 16 // wValidBitsPerSample
+ },
+ KSAUDIO_SPEAKER_STEREO, // dwChannelMask
+ KSDATAFORMAT_SUBTYPE_PCM // SubFormat
+ },
+ // 4
+ {
+ // Format
+ {
+ WAVE_FORMAT_EXTENSIBLE, // wFormatTag
+ 2, // nChannels
+ 96000, // nSamplesPerSec
+ 384000, // nAvgBytesPerSec
+ 4, // nBlockAlign
+ 16, // wBitsPerSample
+ 22 // cbSize
+ },
+ // Samples
+ {
+ 16 // wValidBitsPerSample
+ },
+ KSAUDIO_SPEAKER_STEREO, // dwChannelMask
+ KSDATAFORMAT_SUBTYPE_PCM // SubFormat
+ },
+};
diff --git a/audio/tests/wavetest/PropertyHelper.cpp b/audio/tests/PinResourceHelpers/PropertyHelper.cpp
index fb60d3cc..6e85e53e 100644
--- a/audio/tests/wavetest/PropertyHelper.cpp
+++ b/audio/tests/PinResourceHelpers/PropertyHelper.cpp
@@ -4,7 +4,7 @@
//
// Module Name:
//
-// EndpointPropertyHelpers.cpp
+// PropertyHelper.cpp
//
// Abstract:
//
@@ -14,7 +14,8 @@
#include "PreComp.h"
#include <AVEndpointKeys.h>
#include <Functiondiscoverykeys_devpkey.h>
-#include "PropertyHelper.h"
+#include <devpkey.h>
+#include <PropertyHelper.h>
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
@@ -722,6 +723,8 @@ HRESULT IsFormatSupported
return hr;
}
+ CoTaskMemFree(pKsRequestedFormat);
+
return hr;
}
@@ -1093,3 +1096,168 @@ HRESULT GetAvailiablePinInstanceCount
return hr;
}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// IsAVStream
+//
+// Check if audio device is AVStream
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT IsAVStream
+(
+ IMMDevice* pDevice,
+ bool* pIsAVStream
+)
+{
+ HRESULT hr = S_OK;
+ wil::com_ptr_nothrow<IMMDevice> spDevnodeDevice;
+ wil::com_ptr_nothrow<IPropertyStore> spPnpProperties;
+ wil::unique_prop_variant varDeviceService;
+
+ *pIsAVStream = false;
+
+ // Find the associated PnP device
+ if (!VERIFY_SUCCEEDED(hr = GetPnpDevnodeFromMMDevice(pDevice, &spDevnodeDevice))) {
+ return hr;
+ }
+
+ // Open pnp device property store
+ if (!VERIFY_SUCCEEDED(hr = spDevnodeDevice->OpenPropertyStore(STGM_READ, &spPnpProperties))) {
+ return hr;
+ }
+
+ // Read the DEVPKEY_Device_Service
+ if (!VERIFY_SUCCEEDED(hr = spPnpProperties->GetValue((REFPROPERTYKEY)DEVPKEY_Device_Service, &varDeviceService))) {
+ return hr;
+ }
+
+ if (!VERIFY_IS_TRUE(varDeviceService.vt == VT_LPWSTR && varDeviceService.pwszVal != nullptr)) {
+ hr = E_FAIL;
+ return hr;
+ }
+
+ if (0 == _wcsicmp(varDeviceService.pwszVal, L"usbaudio") || 0 == _wcsicmp(varDeviceService.pwszVal, L"BthHFAud") || 0 == _wcsicmp(varDeviceService.pwszVal, L"BthA2dp")) {
+ *pIsAVStream = true;
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// IsBluetooth
+//
+// Check if audio device is Bluetooth
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT IsBluetooth
+(
+ IMMDevice* pDevice,
+ bool* pIsBluetooth
+)
+{
+ HRESULT hr = S_OK;
+ wil::com_ptr_nothrow<IPropertyStore> spPropertyStore;
+ wil::unique_prop_variant varIsBluetooth;
+
+ *pIsBluetooth = false;
+
+ // Open pnp device property store
+ if (!VERIFY_SUCCEEDED(hr = pDevice->OpenPropertyStore(STGM_READ, &spPropertyStore))) {
+ return hr;
+ }
+
+ // Read the PKEY_Endpoint_IsBluetooth
+ hr = spPropertyStore->GetValue((REFPROPERTYKEY)PKEY_Endpoint_IsBluetooth, &varIsBluetooth);
+ if (hr != S_OK) {
+ return hr;
+ }
+
+ if (varIsBluetooth.vt == VT_BOOL)
+ {
+ *pIsBluetooth = varIsBluetooth.boolVal == VARIANT_TRUE ? true : false;
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// IsSideband
+//
+// Check if audio device is side band
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT IsSideband
+(
+ IMMDevice* pDevice,
+ bool* pIsSideband
+)
+{
+ HRESULT hr = S_OK;
+ wil::com_ptr_nothrow<IPropertyStore> spPropertyStore;
+ wil::unique_prop_variant varIsSideband;
+
+ *pIsSideband = false;
+
+ // Open pnp device property store
+ if (!VERIFY_SUCCEEDED(hr = pDevice->OpenPropertyStore(STGM_READ, &spPropertyStore))) {
+ return hr;
+ }
+
+ // Read the PKEY_Endpoint_IsBluetooth
+ hr = spPropertyStore->GetValue((REFPROPERTYKEY)PKEY_Endpoint_IsSideband, &varIsSideband);
+ if (hr != S_OK) {
+ return hr;
+ }
+
+ if (varIsSideband.vt == VT_BOOL)
+ {
+ *pIsSideband = varIsSideband.boolVal == VARIANT_TRUE ? true : false;
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// GetPnpDevnodeFromMMDeivce
+//
+// Get pnp devnode from mm device
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+HRESULT GetPnpDevnodeFromMMDevice
+(
+ IMMDevice* pDevice,
+ IMMDevice** pDevnodeDevice
+)
+{
+ HRESULT hr = S_OK;
+ wil::com_ptr_nothrow<IMMDeviceEnumerator> spEnumerator;
+ wil::com_ptr_nothrow<IPropertyStore> spProps;
+ wil::com_ptr_nothrow<IMMDevice> spDevnodeAsDevice;
+ wil::com_ptr_nothrow<IPropertyStore> spDevnodeProps;
+ wil::unique_prop_variant varDevnode;
+
+ // Create an enumerator
+ if (!VERIFY_SUCCEEDED(hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void **)&spEnumerator))) {
+ return hr;
+ }
+
+ // Read the PKEY_Endpoint_Devnode
+ if (!VERIFY_SUCCEEDED(hr = pDevice->OpenPropertyStore(STGM_READ, &spProps))) {
+ return hr;
+ }
+ if (!VERIFY_SUCCEEDED(hr = spProps->GetValue(PKEY_Endpoint_Devnode, &varDevnode))) {
+ return hr;
+ }
+
+ // Get the devnode as an IMMDevice
+ if (!VERIFY_SUCCEEDED(hr = spEnumerator->GetDevice(varDevnode.pwszVal, &spDevnodeAsDevice))) {
+ return hr;
+ }
+ *pDevnodeDevice = spDevnodeAsDevice.detach();
+
+ return hr;
+}
diff --git a/audio/tests/wavetest/TestResource.cpp b/audio/tests/PinResourceHelpers/TestResource.cpp
index 67f3ca79..f3762b84 100644
--- a/audio/tests/wavetest/TestResource.cpp
+++ b/audio/tests/PinResourceHelpers/TestResource.cpp
@@ -13,8 +13,8 @@
// -------------------------------------------------------------------------------
#include "PreComp.h"
-#include "HalfApp.h"
-#include "TestResource.h"
+#include <HalfApp.h>
+#include <TestResource.h>
using namespace WEX::Logging;
using namespace WEX::TestExecution;
@@ -328,4 +328,4 @@ LPWSTR CPinTestResource::PinName(EndpointConnectorType eConnectorType)
default:
return L"UNKNOWN";
}
-} \ No newline at end of file
+}
diff --git a/audio/tests/wavetest/TestResourceHelper.h b/audio/tests/PinResourceHelpers/TestResourceHelper.h
index 24bae634..08fafa23 100644
--- a/audio/tests/wavetest/TestResourceHelper.h
+++ b/audio/tests/PinResourceHelpers/TestResourceHelper.h
@@ -13,6 +13,8 @@
// -------------------------------------------------------------------------------
#pragma once
+#include <HalfApp.h>
+
// ----------------------------------------------------------------------
HRESULT GetProcessingModesForConnector
(
@@ -68,4 +70,4 @@ HRESULT GetSupportedFormatRecordsForConnector
STACKWISE_DATAFLOW dataFlow,
ULONG* pCount,
FORMAT_RECORD** ppFormatRecords
-); \ No newline at end of file
+);
diff --git a/audio/tests/wavetest/HalfApp.h b/audio/tests/wavetest/HalfApp.h
deleted file mode 100644
index 1bf14de9..00000000
--- a/audio/tests/wavetest/HalfApp.h
+++ /dev/null
@@ -1,195 +0,0 @@
-// ------------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft. All rights reserved.
-//
-// File Name:
-//
-// HalfApp.h
-//
-// Abstract:
-//
-// CHalfApp declarations
-//
-// -------------------------------------------------------------------------------
-#pragma once
-
-#define BUF_LEN_IN_MS 1000 // 1 second
-
-class CHalfApp
-{
-public:
- // Basic pin infos
- wil::com_ptr_nothrow<IMMDevice> m_pDevice;
- wil::unique_cotaskmem_string m_pwstrDeviceId;
- wil::unique_cotaskmem_string m_pwstrDeviceFriendlyName;
- STACKWISE_DATAFLOW m_DataFlow;
- EndpointConnectorType m_ConnectorType;
- UINT m_uConnectorId;
- GUID m_Mode;
- ULONG m_cModes;
- GUID* m_pModes; // All processing modes
-
- // Formats
- wil::unique_cotaskmem_ptr<WAVEFORMATEX> m_pPreferredFormat;
- UINT32 m_u32DefaultPeriodicityInFrames;
- UINT32 m_u32FundamentalPeriodicityInFrames;
- UINT32 m_u32MinPeriodicityInFrames;
- UINT32 m_u32MaxPeriodicityInFrames;
-
- PFORMAT_RECORD m_pFormatRecords;
- ULONG m_cFormatRecords;
-
- wil::unique_cotaskmem_ptr<WAVEFORMATEX> m_pCurrentFormat;
- UINT32 m_u32CurrentDefaultPeriodicityInFrames;
- UINT32 m_u32CurrentFundamentalPeriodicityInFrames;
- UINT32 m_u32CurrentMinPeriodicityInFrames;
- UINT32 m_u32CurrentMaxPeriodicityInFrames;
-
- // Audio endpoint interfaces
- wil::com_ptr_nothrow<IAudioDeviceEndpoint> m_pAudioDeviceEndpoint;
- wil::com_ptr_nothrow<IAudioEndpoint> m_pAudioEndpoint;
- wil::com_ptr_nothrow<IAudioEndpointControl> m_pAudioEndpointControl;
- wil::com_ptr_nothrow<IAudioEndpointRT> m_pAudioEndpointRT;
-
- // Data buffer
- wil::unique_hlocal_ptr<BYTE> m_pbSineToneDataBuffer;
- DWORD m_dwSineToneDataBufferSize;
- DWORD m_dwSineToneDataBufferPosition;
-
- // Stream
- HNSTIME m_hnsPeriod = 0;
- FLOAT32 m_f32EndpointFrameRate = 0.F;
- HNSTIME m_hnsEndpointLatency = 0;
- bool m_bIsEventCapable = false;
- bool m_bStreamInitialized = false;
- volatile bool m_bStreamThreadTerminate = false;
- bool m_bYieldActive = false;
- bool m_bIsBackupTimerRequired = true;
-
- wil::unique_handle m_hStreamThread;
-
- LPTHREAD_START_ROUTINE m_pStreamRoutine = nullptr;
- wil::unique_event_nothrow m_hProcessThreadStartedEvent;
- wil::unique_event_nothrow m_hTerminate;
- wil::unique_event_nothrow m_hEndpointBufferCompleteEvent;
- wil::unique_handle m_hTimer;
-
- wil::critical_section m_CritSec;
-
- typedef enum
- {
- ET_DO_NOTHING = 0x00,
- ET_TERMINATE = 0x01,
- ET_OBJECT_BUFFER_COMPLETE = 0x02,
- ET_CLIENT_RELEASE_BUFFER = 0x04,
- ET_TIMER = 0x08,
- ET_PAUSE_PUMP = 0x10,
- ET_RESUME_PUMP = 0x20,
- } TEventType;
-
- CHalfApp(
- _In_ IMMDevice* pDevice,
- _In_ LPWSTR pwstrAudioEndpointId,
- _In_ LPWSTR pwstrAudioEndpointFriendlyName,
- _In_ STACKWISE_DATAFLOW dataFlow,
- _In_ EndpointConnectorType eConnectorType,
- _In_ UINT uConnectorId,
- _In_ GUID mode,
- _In_ ULONG cModes,
- _In_ GUID* pModes,
- _In_ ULONG cFormatRecords,
- _In_ PFORMAT_RECORD pFormatRecords,
- _In_ PWAVEFORMATEX pPreferredFormat,
- _In_ UINT32 u32DefaultPeriodicityInFrames,
- _In_ UINT32 u32FundamentalPeriodicityInFrames,
- _In_ UINT32 u32MinPeriodicityInFrames,
- _In_ UINT32 u32MaxPeriodicityInFrames
- )
- : m_DataFlow(dataFlow)
- , m_ConnectorType(eConnectorType)
- , m_uConnectorId(uConnectorId)
- , m_cModes(cModes)
- , m_cFormatRecords(cFormatRecords)
- , m_u32DefaultPeriodicityInFrames(u32DefaultPeriodicityInFrames)
- , m_u32FundamentalPeriodicityInFrames(u32FundamentalPeriodicityInFrames)
- , m_u32MinPeriodicityInFrames(u32MinPeriodicityInFrames)
- , m_u32MaxPeriodicityInFrames(u32MaxPeriodicityInFrames)
- , m_u32CurrentDefaultPeriodicityInFrames(u32DefaultPeriodicityInFrames)
- , m_u32CurrentFundamentalPeriodicityInFrames(u32FundamentalPeriodicityInFrames)
- , m_u32CurrentMinPeriodicityInFrames(u32MinPeriodicityInFrames)
- , m_u32CurrentMaxPeriodicityInFrames(u32MaxPeriodicityInFrames)
- {
- m_pDevice = pDevice;
- m_pAudioDeviceEndpoint = nullptr;
- m_pAudioEndpointControl = nullptr;
-
- m_pwstrDeviceId = wil::make_cotaskmem_string_nothrow(pwstrAudioEndpointId, wcslen(pwstrAudioEndpointId));
- m_pwstrDeviceFriendlyName = wil::make_cotaskmem_string_nothrow(pwstrAudioEndpointFriendlyName, wcslen(pwstrAudioEndpointFriendlyName));
- m_Mode = mode;
-
- m_pModes = new GUID[cModes];
- memcpy(m_pModes, pModes, sizeof(GUID)*cModes);
- m_pFormatRecords = new FORMAT_RECORD[cFormatRecords];
- memcpy(m_pFormatRecords, pFormatRecords, sizeof(FORMAT_RECORD)*cFormatRecords);
-
- CloneWaveFormat(pPreferredFormat, wil::out_param(m_pPreferredFormat));
- CloneWaveFormat(pPreferredFormat, wil::out_param(m_pCurrentFormat)); // Use preferred format as current format
- }
-
- ~CHalfApp(void)
- {
- if (m_pModes)
- delete[] m_pModes;
- if (m_pFormatRecords)
- delete[] m_pFormatRecords;
- }
-
- // Audio endpoint interfaces
- HRESULT InitializeEndpoint();
- HRESULT ReleaseEndpoint();
- HRESULT StartEndpoint();
- HRESULT StopEndpoint();
- HRESULT ResetEndpoint();
-
- // Sine tone data buffer
- HRESULT CreateSineToneDataBuffer(WAVEFORMATEX* pWfx);
- HRESULT ReleaseSineToneDataBuffer();
-
-
-
-
- // Stream
- HRESULT InitializeAndSetBuffer(HNSTIME hnsPeriod, UINT32 u32LatencyCoefficient);
- HRESULT InitializeStream(HNSTIME requestedPeriodicity, UINT32 u32LatencyCoefficient);
- HRESULT CleanupStream();
- HRESULT StartStream();
- HRESULT StopStream();
- static DWORD CALLBACK RenderStreamRoutine(PVOID lpParameter);
- static DWORD CALLBACK CaptureStreamRoutine(PVOID lpParameter);
- void SignalAndWaitForThread();
-
-
-
- HRESULT SetTimer(HANDLE timer, HNSTIME timeDuration, bool fireImmediatley);
- void CancelTimer(HANDLE timer);
- HRESULT GetPosition(UINT64* pu64Position, UINT64* pu64hnsQPCPosition);
-
- // Multiple pin instances
- HRESULT GetCurrentAvailiablePinInstanceCount(UINT32* pAvailablePinInstanceCount);
- HRESULT GetSecondHalfApp(AUDIO_SIGNALPROCESSINGMODE secondMode, CHalfApp** ppSecondHalfApp);
-
- // Only for loopback testcases
- HRESULT GetHostHalfApp(CHalfApp** ppHostHalfApp);
-};
-
-// {571BF784-A9D6-420A-BCA0-C579A8710236}
-DEFINE_GUID(IID_IHalfAppContainer,
- 0x571bf784, 0xa9d6, 0x420a, 0xbc, 0xa0, 0xc5, 0x79, 0xa8, 071, 0x02, 0x36);
-
-DECLARE_INTERFACE_IID_(
-IHalfAppContainer,
-IUnknown,
-"571BF784-A9D6-420A-BCA0-C579A8710236")
-{
- STDMETHOD(GetHalfApp)(THIS_ CHalfApp ** ppHalfApp) PURE;
-};
diff --git a/audio/tests/wavetest/PreComp.h b/audio/tests/wavetest/PreComp.h
index 2044d6b1..76210090 100644
--- a/audio/tests/wavetest/PreComp.h
+++ b/audio/tests/wavetest/PreComp.h
@@ -24,13 +24,11 @@
#include <Audioclient.h>
#include <mmdeviceapi.h>
#include <mmdeviceapip.h>
-#include <devicetopology.h>
#include <devicetopologyp.h>
#include <propvarutil.h>
#include <wil\com.h>
-#include <winioctl.h>
#include <KsLib.h>
#include <Waveutil.h>
#include <aecommon.h>
@@ -47,108 +45,3 @@
#define WARN(log, ...) BasicLogPrintf( log, XWARN, 1, __VA_ARGS__ )
#define BLOCK(log, ...) BasicLogPrintf( log, XBLOCK, 1, __VA_ARGS__ )
#define ERR(log, ...) BasicLogPrintf( log, XFAIL, 1, __VA_ARGS__ )
-
-// ------------------------------------------------------------------------------
-// Data flow
-enum STACKWISE_DATAFLOW { render, capture };
-
-// ------------------------------------------------------------------------------
-// Structs used to hold results of format records
-typedef struct
-{
- WAVEFORMATEXTENSIBLE wfxEx;
- UINT32 fundamentalPeriodInFrames;
- UINT32 defaultPeriodInFrames;
- UINT32 minPeriodInFrames;
- UINT32 maxPeriodInFrames;
- UINT32 maxPeriodInFramesExtended;
-} FORMAT_RECORD, *PFORMAT_RECORD;
-
-// ----------------------------------------------------------
-// Parameters for test sine tone
-#define TEST_AMPLITUDE 1.0f
-#define TEST_FREQUENCY 200.0f
-
-// ----------------------------------------------------------
-// Predefined format list for offload streaming
-#define COUNT_FORMATS 4
-
-static WAVEFORMATEXTENSIBLE ListofFormats[COUNT_FORMATS] =
-{
- // 1
- {
- // Format
- {
- WAVE_FORMAT_EXTENSIBLE, // wFormatTag
- 2, // nChannels
- 44100, // nSamplesPerSec
- 176400, // nAvgBytesPerSec
- 4, // nBlockAlign
- 16, // wBitsPerSample
- 22 // cbSize
- },
- // Samples
- {
- 16 // wValidBitsPerSample
- },
- KSAUDIO_SPEAKER_STEREO, // dwChannelMask
- KSDATAFORMAT_SUBTYPE_PCM // SubFormat
- },
- // 2
- {
- // Format
- {
- WAVE_FORMAT_EXTENSIBLE, // wFormatTag
- 2, // nChannels
- 48000, // nSamplesPerSec
- 192000, // nAvgBytesPerSec
- 4, // nBlockAlign
- 16, // wBitsPerSample
- 22 // cbSize
- },
- // Samples
- {
- 16 // wValidBitsPerSample
- },
- KSAUDIO_SPEAKER_STEREO, // dwChannelMask
- KSDATAFORMAT_SUBTYPE_PCM // SubFormat
- },
- // 3
- {
- // Format
- {
- WAVE_FORMAT_EXTENSIBLE, // wFormatTag
- 2, // nChannels
- 88200, // nSamplesPerSec
- 352800, // nAvgBytesPerSec
- 4, // nBlockAlign
- 16, // wBitsPerSample
- 22 // cbSize
- },
- // Samples
- {
- 16 // wValidBitsPerSample
- },
- KSAUDIO_SPEAKER_STEREO, // dwChannelMask
- KSDATAFORMAT_SUBTYPE_PCM // SubFormat
- },
- // 4
- {
- // Format
- {
- WAVE_FORMAT_EXTENSIBLE, // wFormatTag
- 2, // nChannels
- 96000, // nSamplesPerSec
- 384000, // nAvgBytesPerSec
- 4, // nBlockAlign
- 16, // wBitsPerSample
- 22 // cbSize
- },
- // Samples
- {
- 16 // wValidBitsPerSample
- },
- KSAUDIO_SPEAKER_STEREO, // dwChannelMask
- KSDATAFORMAT_SUBTYPE_PCM // SubFormat
- },
-}; \ No newline at end of file
diff --git a/audio/tests/wavetest/PropertyHelper.h b/audio/tests/wavetest/PropertyHelper.h
deleted file mode 100644
index 9f01a9a7..00000000
--- a/audio/tests/wavetest/PropertyHelper.h
+++ /dev/null
@@ -1,190 +0,0 @@
-// ------------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft. All rights reserved.
-//
-// Module Name:
-//
-// PropertyHelpers.h
-//
-// Abstract:
-//
-// Header for common helpers/defines of property
-//
-// -------------------------------------------------------------------------------
-#pragma once
-
-#define kSystemDefaultPeriod 100000 // 10 milliseconds
-#define kSystemMinPeriodForNonRTCapableEndpoints 20000 // 2 milliseconds
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-// ----------------------------------------------------------------------
-HRESULT GetConnectorId
-(
- IMMDevice* pDevice,
- EndpointConnectorType eConnectorType,
- bool* hasConnector,
- UINT* pConnectorId
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetEndpointFriendlyName
-(
- IMMDevice* pDevice,
- LPWSTR* ppwszEndpointName
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetAudioFilterAsDevice
-(
- IMMDevice* pDevice,
- IMMDevice** ppAudioFilterAsDevice
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetCachedProcessingModes
-(
- IMMDevice* pDevice,
- EndpointConnectorType eConnectorType,
- ULONG *pCount,
- AUDIO_SIGNALPROCESSINGMODE **ppModes
-);
-
-
-
-
-
-
-
-
-
-
-
-
-// ----------------------------------------------------------------------
-HRESULT GetProcessingModes
-(
- IMMDevice* pDevice,
- UINT pinId,
- ULONG *pCount,
- AUDIO_SIGNALPROCESSINGMODE **ppModes
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetCachedSupportedFormatRecords
-(
- IMMDevice* pDevice,
- EndpointConnectorType eConnectorType,
- AUDIO_SIGNALPROCESSINGMODE mode,
- ULONG *pCount,
- FORMAT_RECORD **ppFormatRecords
-);
-
-
-
-
-
-
-
-
-
-
-
-
-
-// ----------------------------------------------------------------------
-HRESULT GetSupportedFormatRecords
-(
- IMMDevice* pDevice,
- UINT pinId,
- EndpointConnectorType eConnectorType,
- AUDIO_SIGNALPROCESSINGMODE mode,
- STACKWISE_DATAFLOW dataFlow,
- ULONG *pCount,
- FORMAT_RECORD **ppFormatRecords
-);
-
-// ----------------------------------------------------------------------
-HRESULT IsFormatSupported
-(
- IMMDevice* pDevice,
- UINT pinId,
- WAVEFORMATEX *pWfx,
- BOOL* pbSupported
-);
-
-// ----------------------------------------------------------------------
-HRESULT DiscoverPeriodicityCharacteristicsForFormat
-(
- IMMDevice* pDevice,
- EndpointConnectorType eConnectorType,
- AUDIO_SIGNALPROCESSINGMODE mode,
- WAVEFORMATEX *pWfx,
- STACKWISE_DATAFLOW dataFlow,
- UINT32 *pDefaultPeriodicityInFrames,
- UINT32 *pFundamentalPeriodicityInFrames,
- UINT32 *pMinPeriodicityInFrames,
- UINT32 *pMaxPeriodicityInFrames,
- UINT32 *pMaxPeriodicityInFramesExtended
-);
-
-// ----------------------------------------------------------------------
-HRESULT CheckConnectorSupportForPeriodicity
-(
- IMMDevice* pDevice,
- EndpointConnectorType eConnectorType,
- AUDIO_SIGNALPROCESSINGMODE mode,
- WAVEFORMATEX *pWfx,
- STACKWISE_DATAFLOW dataFlow,
- HNSTIME RequestedPeriodicity,
- UINT32 *pActualPeriodicityInFrames
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetCachedDefaultFormat
-(
- IMMDevice* pDevice,
- EndpointConnectorType eConnectorType,
- WAVEFORMATEX** ppDefaultFormat
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetProposedFormatForProcessingMode
-(
- IMMDevice* pDevice,
- UINT pinId,
- AUDIO_SIGNALPROCESSINGMODE mode,
- WAVEFORMATEX **ppProposedFormat
-);
-
-// ----------------------------------------------------------------------
-HRESULT GetAvailiablePinInstanceCount
-(
- IMMDevice* pDevice,
- UINT pinId,
- UINT32* pAvailablePinInstanceCount
-);
diff --git a/audio/tests/wavetest/TestResource.h b/audio/tests/wavetest/TestResource.h
deleted file mode 100644
index 49dee5a5..00000000
--- a/audio/tests/wavetest/TestResource.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// ------------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft. All rights reserved.
-//
-// File Name:
-//
-// TestResource.h
-//
-// Abstract:
-//
-// TAEF Test Resource
-//
-// -------------------------------------------------------------------------------
-#include "WaveTestTaef.h"
-
-class CPinTestResource :
- public WEX::TestExecution::ITestResource,
- public IHalfAppContainer
-{
-public:
- //IUnknown
- STDMETHODIMP_(ULONG) AddRef();
- STDMETHODIMP_(ULONG) Release();
- STDMETHODIMP QueryInterface(
- __in REFIID riid,
- __deref_out VOID **ppvObject
- );
- // ITestResouce
- STDMETHODIMP GetGuid(GUID* pGuid);
- STDMETHODIMP SetGuid(GUID guid);
- STDMETHODIMP GetValue(BSTR name, BSTR* pValue);
- STDMETHODIMP SetValue(BSTR name, BSTR value);
-
- //IHalfAppContainer
- STDMETHODIMP GetHalfApp(CHalfApp ** ppHalfApp);
-
- static HRESULT STDMETHODCALLTYPE CreateInstance(
- CHalfApp * pHalf,
- REFGUID guid,
- WEX::TestExecution::ITestResource ** ppOut
- );
-
-private:
-
- CPinTestResource();
- ~CPinTestResource();
-
- HRESULT STDMETHODCALLTYPE Initialize(
- CHalfApp * pHalf,
- REFGUID guid
- );
-
- LPWSTR ModeName(REFGUID guidMode);
- LPWSTR PinName(EndpointConnectorType eConnectorType);
-
- CComBSTR m_szType;
- CComBSTR m_szName;
- CComBSTR m_szId;
- CComBSTR m_szMode;
- CComBSTR m_szPin;
-
- CAutoPtr<CHalfApp> m_spHalfApp;
-
- ULONG m_cRef;
- GUID m_guid;
-}; \ No newline at end of file
diff --git a/audio/tests/wavetest/TestResourceBuild.cpp b/audio/tests/wavetest/TestResourceBuild.cpp
index 51cce52d..5ca2ff0d 100644
--- a/audio/tests/wavetest/TestResourceBuild.cpp
+++ b/audio/tests/wavetest/TestResourceBuild.cpp
@@ -12,8 +12,8 @@
//
// ------------------------------------------------------------------------------
#include "PreComp.h"
-#include "TestResource.h"
-#include "PropertyHelper.h"
+#include <TestResource.h>
+#include <PropertyHelper.h>
using namespace WEX::Common;
using namespace WEX::Logging;
@@ -30,32 +30,18 @@ using namespace WEX::TestExecution;
HRESULT CreateTestResource
(
ResourceList& resourceList,
- LPWSTR deviceId,
- LPWSTR deviceName,
- IMMDevice* pDevice,
- STACKWISE_DATAFLOW dataFlow,
- EndpointConnectorType eConnectorType,
- UINT uConnectorId,
- AUDIO_SIGNALPROCESSINGMODE mode,
- ULONG cModes,
- AUDIO_SIGNALPROCESSINGMODE* pModes,
- ULONG cFormatRecords,
- PFORMAT_RECORD pFormatRecords,
- PWAVEFORMATEX pPreferredFormat,
- UINT32 defaultPeriodicityInFrames,
- UINT32 fundamentalPeriodicityInFrames,
- UINT32 minPeriodicityInFrames,
- UINT32 maxPeriodicityInFrames
+ DeviceDescriptor descriptor
)
{
HRESULT hr = S_OK;
+
CComHeapPtr<CHalfApp> spHalfApp;
wil::com_ptr_nothrow<ITestResource> spTestResource;
GUID ResourceGUID;
CComBSTR szResourceName;
// Create HalfApp
- spHalfApp.Attach(new CHalfApp(pDevice, deviceId, deviceName, dataFlow, eConnectorType, uConnectorId, mode, cModes, pModes, cFormatRecords, pFormatRecords, pPreferredFormat, defaultPeriodicityInFrames, fundamentalPeriodicityInFrames, minPeriodicityInFrames, maxPeriodicityInFrames));
+ spHalfApp.Attach(new CHalfApp(descriptor));
if (!VERIFY_IS_NOT_NULL(spHalfApp)) {
hr = E_OUTOFMEMORY;
return hr;
@@ -327,6 +313,7 @@ HRESULT AddTestResourceForConnector
UINT32 u32MinPeriodicityInFrames;
UINT32 u32MaxPeriodicityInFrames;
UINT32 u32MaxPeriodicityInFramesExtended;
+ bool isAVStream = false;
// Get connector id
if (!VERIFY_SUCCEEDED(hr = GetConnectorId(pDevice, eConnectorType, &bHasConnector, &uConnectorId))) {
@@ -338,6 +325,7 @@ HRESULT AddTestResourceForConnector
Log::Comment(String().Format(L"Adding Test Resource for pin [%u]:", (uConnectorId & PARTID_MASK)));
+
// Get all signal processing modes for connector
if (!VERIFY_SUCCEEDED(hr = GetProcessingModesForConnector(pDevice, uConnectorId, eConnectorType, &cModes, &spModes))) {
return hr;
@@ -345,6 +333,7 @@ HRESULT AddTestResourceForConnector
// Loop through each mode, get preferred format and list of formats and create test resource for each mode
for (ULONG i = 0; i < cModes; i++) {
+
mode = spModes[i];
if (!VERIFY_SUCCEEDED(hr = GetSupportedFormatRecordsForConnector(pDevice, uConnectorId, eConnectorType, mode, dataFlow, &cFormatRecords, &spFormatRecords))) {
@@ -358,8 +347,32 @@ HRESULT AddTestResourceForConnector
if (!VERIFY_SUCCEEDED(hr = GetPreferredFormatPeriodicityCharacteristicsForConnector(pDevice, eConnectorType, mode, dataFlow, pPreferredFormat.get(), cFormatRecords, spFormatRecords, &u32DefaultPeriodicityInFrames, &u32FundamentalPeriodicityInFrames, &u32MinPeriodicityInFrames, &u32MaxPeriodicityInFrames, &u32MaxPeriodicityInFramesExtended))) {
return hr;
}
-
- if (!VERIFY_SUCCEEDED(hr = CreateTestResource(resourceList, deviceId, deviceName, pDevice, dataFlow, eConnectorType, uConnectorId, mode, cModes, spModes, cFormatRecords, spFormatRecords, pPreferredFormat.get(), u32DefaultPeriodicityInFrames, u32FundamentalPeriodicityInFrames, u32MinPeriodicityInFrames, u32MaxPeriodicityInFrames))) {
+
+ // Check if audio endpoint is AVStream
+ if (!VERIFY_SUCCEEDED(hr = IsAVStream(pDevice, &isAVStream))) {
+ return hr;
+ }
+
+ DeviceDescriptor descriptor = { 0 };
+ descriptor.pDevice = pDevice;
+ descriptor.pwstrAudioEndpointId = deviceId;
+ descriptor.pwstrAudioEndpointFriendlyName = deviceName;
+ descriptor.dataFlow = dataFlow;
+ descriptor.eConnectorType = eConnectorType;
+ descriptor.uConnectorId = uConnectorId;
+ descriptor.mode = mode;
+ descriptor.cModes = cModes;
+ descriptor.pModes = spModes;
+ descriptor.cFormatRecords = cFormatRecords;
+ descriptor.pFormatRecords = spFormatRecords;
+ descriptor.pPreferredFormat = pPreferredFormat.get();
+ descriptor.u32DefaultPeriodicityInFrames = u32DefaultPeriodicityInFrames;
+ descriptor.u32FundamentalPeriodicityInFrames = u32FundamentalPeriodicityInFrames;
+ descriptor.u32MinPeriodicityInFrames = u32MinPeriodicityInFrames;
+ descriptor.u32MaxPeriodicityInFrames = u32MaxPeriodicityInFrames;
+ descriptor.bIsAVStream = isAVStream;
+
+ if (!VERIFY_SUCCEEDED(hr = CreateTestResource(resourceList, descriptor))) {
return hr;
}
}
diff --git a/audio/tests/wavetest/WaveTestTaef.cpp b/audio/tests/wavetest/WaveTestTaef.cpp
index dacf44ab..be5d47f3 100644
--- a/audio/tests/wavetest/WaveTestTaef.cpp
+++ b/audio/tests/wavetest/WaveTestTaef.cpp
@@ -164,7 +164,7 @@ void WDMAudio::WaveTest::TAEF_StreamMultipleModes()
RUN_TEST_CASE(Test_StreamMultipleModes)
}
-void WDMAudio::WaveTest::TAEF_VerifyPinSupportsPullMode()
+void WDMAudio::WaveTest::TAEF_VerifyPinWaveRTConformance()
{
- RUN_TEST_CASE(Test_VerifyPinSupportsPullMode)
-} \ No newline at end of file
+ RUN_TEST_CASE(Test_VerifyPinWaveRTConformance)
+}
diff --git a/audio/tests/wavetest/WaveTestTaef.h b/audio/tests/wavetest/WaveTestTaef.h
index a8d38305..8c87a7f8 100644
--- a/audio/tests/wavetest/WaveTestTaef.h
+++ b/audio/tests/wavetest/WaveTestTaef.h
@@ -13,7 +13,7 @@
// -------------------------------------------------------------------------------
#pragma once
-#include "HalfApp.h"
+#include <HalfApp.h>
extern IBasicLog* g_pBasicLog;
@@ -41,6 +41,7 @@ namespace WDMAudio
TEST_CLASS_PROPERTY(L"Kits.SupportedOS", L"Windows v10.0 Server x64")
TEST_CLASS_PROPERTY(L"Kits.MinRelease", L"19H1")
TEST_CLASS_PROPERTY(L"Kits.CorePackageComposition", L"Full")
+ TEST_CLASS_PROPERTY(L"Kits.CorePackageComposition", L"OnecoreUAP")
TEST_CLASS_PROPERTY(L"Kits.IsInProc", L"True")
TEST_CLASS_PROPERTY(L"Kits.Parameter", L"DeviceID")
TEST_CLASS_PROPERTY(L"Kits.Parameter.DeviceID.Description", L"Device id of device under test")
@@ -109,7 +110,7 @@ namespace WDMAudio
TEST_METHOD_PROPERTY(L"ResourceSelection", L"@Id = '*RAW' OR @Id = '*DEFAULT'")
END_TEST_METHOD()
- BEGIN_TEST_METHOD(TAEF_VerifyPinSupportsPullMode)
+ BEGIN_TEST_METHOD(TAEF_VerifyPinWaveRTConformance)
TEST_METHOD_PROPERTY(L"HCKCategory", L"Functional")
TEST_METHOD_PROPERTY(L"HCKCategory", L"Certification")
TEST_METHOD_PROPERTY(L"TestClassification:Scope", L"Feature")
diff --git a/audio/tests/wavetest/comptest.cpp b/audio/tests/wavetest/comptest.cpp
index ef41972c..db823156 100644
--- a/audio/tests/wavetest/comptest.cpp
+++ b/audio/tests/wavetest/comptest.cpp
@@ -17,8 +17,8 @@
#include "tests.h"
// ------------------------------------------------------------------------------
-// Test_VerifyPinSupportsPullMode: Test the requirement that WaveRT drivers must support pull mode audio streaming technology.
-void Test_VerifyPinSupportsPullMode(void)
+// Test_VerifyPinSupportsPullMode: Test the requirement that new drivers must be WaveRT and WaveRT drivers must support event driven audio streaming technology.
+void Test_VerifyPinWaveRTConformance(void)
{
CHalfApp* pHalfApp = g_pWaveTest->m_pHalf;
BOOL bIsRTCapable = false;
@@ -28,10 +28,17 @@ void Test_VerifyPinSupportsPullMode(void)
VERIFY_SUCCEEDED(pHalfApp->m_pAudioDeviceEndpoint->GetRTCaps(&bIsRTCapable));
- // Only require pull mode for WaveRT drivers
+ // Check for our new requirement - new drivers must be WaveRT. Here we skip the test on AVStream (UAC1/HFP/A2dp)
+ // For other old drivers that are not WaveRT, may issue Errata to cover the failure.
+ if (!pHalfApp->m_bIsAVStream)
+ {
+ VERIFY_IS_TRUE(bIsRTCapable);
+ }
+
+ // Only require event driven for WaveRT drivers
if (bIsRTCapable)
{
VERIFY_SUCCEEDED(pHalfApp->m_pAudioDeviceEndpoint->GetEventDrivenCapable(&bIsEventCapable));
VERIFY_IS_TRUE(bIsEventCapable);
}
-} \ No newline at end of file
+}
diff --git a/audio/tests/wavetest/tests.h b/audio/tests/wavetest/tests.h
index 38a6aaa1..e3ae0691 100644
--- a/audio/tests/wavetest/tests.h
+++ b/audio/tests/wavetest/tests.h
@@ -24,4 +24,4 @@ void Test_LoopbackStreamDifferentFormat(void);
void Test_StreamMultipleModes(void);
// Compliance test
-void Test_VerifyPinSupportsPullMode(void); \ No newline at end of file
+void Test_VerifyPinWaveRTConformance(void); \ No newline at end of file