Compare commits

...
121 Commits
Author SHA1 Message Date
Mike Rodriguez d7244969b2 Merge pull request #487 from LizardByte/sunshine
ci: workflow updates
2026-06-22 15:00:18 -07:00
dependabot[bot] 7b33f5e4d2 build(deps): bump actions/checkout from 6.0.3 to 7.0.0 in the github-actions group (#10)
build(deps): bump actions/checkout in the github-actions group

Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout).


Updates `actions/checkout` from 6.0.3 to 7.0.0
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/df4cb1c069e1874edd31b4311f1884172cec0e10...9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-19 10:53:54 -04:00
dependabot[bot] de6ba98ee5 build(deps): bump actions/checkout from 6.0.2 to 6.0.3 in the github-actions group (#9)
build(deps): bump actions/checkout in the github-actions group

Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout).


Updates `actions/checkout` from 6.0.2 to 6.0.3
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/de0fac2e4500dabe0009e67214ff5f5447ce83dd...df4cb1c069e1874edd31b4311f1884172cec0e10)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-03 18:50:43 -04:00
David Lane a35fcb8176 chore: Add JetBrains Rider .idea to .gitignore (#7) 2026-05-23 10:17:12 -04:00
David Lane 38c3ec449d chore: migrate wdf to git submodule (#6) 2026-05-23 10:04:17 -04:00
David Lane a9f6065a23 ci: Pin CI runner to windows-2022 (#5) 2026-05-22 22:33:23 -04:00
dependabot[bot] 8a13aa2424 build(deps): bump microsoft/setup-msbuild from 2.0.0 to 3.0.0 (#4)
Bumps [microsoft/setup-msbuild](https://github.com/microsoft/setup-msbuild) from 2.0.0 to 3.0.0.
- [Release notes](https://github.com/microsoft/setup-msbuild/releases)
- [Commits](https://github.com/microsoft/setup-msbuild/compare/6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce...30375c66a4eea26614e0d39710365f22f8b0af57)

---
updated-dependencies:
- dependency-name: microsoft/setup-msbuild
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-22 22:02:55 -04:00
dependabot[bot] 534d4bcdc8 build(deps): bump the github-actions group with 2 updates (#3)
Bumps the github-actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [actions/upload-artifact](https://github.com/actions/upload-artifact).


Updates `actions/checkout` from 4.3.1 to 6.0.2
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/34e114876b0b11c390a56381ad16ebd13914f8d5...de0fac2e4500dabe0009e67214ff5f5447ce83dd)

Updates `actions/upload-artifact` from 4.6.2 to 7.0.1
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/ea165f8d65b6e75b540449e92b4886f43607fa02...043fb46d1a93c77aae656e7c1c64a875d1fc6a0a)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.2
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-22 22:02:14 -04:00
David Lane ce081a3e10 chore: Add Dependabot configuration for updates
Configure Dependabot for GitHub Actions and Git Submodules with scheduled updates.
2026-05-22 21:59:26 -04:00
LizardByte-bot 7d0a0cec4f chore: update GitHub Actions to use commit hashes (#2) 2026-05-22 21:52:15 -04:00
David Lane 8e85cf2a0c ci: Update workflow for concurrency and branch settings (#1) 2026-05-22 21:48:16 -04:00
Mike Rodriguez a660c72e7c Merge pull request #482 from AndreTheAss/codex/fix-multi-monitor-swapchain-449
Fix multi-monitor swapchain threading for issue #449
2026-05-18 15:49:41 -07:00
Mike Rodriguez 17eed4381b Add related software section to README
Added a section to the README for related software tools with descriptions and links.
2026-05-18 15:44:30 -07:00
andre fc499471c1 Fix multi-monitor swapchain threading for issue #449 2026-04-11 17:57:27 +02:00
Mike Rodriguez 052f0aa300 Fix HDR bit depth for Virtual-Display-Driver 2026-04-07 14:52:31 -07:00
Mike Rodriguez 537b13e300 Merge pull request #473 from clickwithclark/patch-1
docs: Add detailed warning about GPU/chipset driver update conflicts
2026-03-17 19:08:51 -07:00
Clark 4efda4e043 docs: Add detailed warning about GPU/chipset driver update conflicts
Expands on the existing driver update safety warning with:
- Step-by-step prevention instructions
- Detailed Safe Mode recovery steps
- Technical explanation of why this happens
- Real-world system examples

Addresses issue #440
2026-02-13 08:21:55 -04:00
Mike Rodriguez 22e3abfc8e Merge branch 'doc/vdd-driver-update-warning' 2026-02-03 08:34:37 -08:00
Mike Rodriguez 2c33d31caa docs: thank ye4241 for WinGet submission 2026-02-03 08:31:02 -08:00
Mike Rodriguez f2bfc1788d docs: add winget install command 2026-02-03 08:30:15 -08:00
Mike Rodriguez a8cf262b51 Merge pull request #469 from VirtualDrivers/doc/vdd-driver-update-warning
docs: add warning for GPU/chipset driver updates
2026-02-03 07:43:06 -08:00
Mike Rodriguez 7968d8b91d docs: add warning for GPU/chipset driver updates 2026-02-03 07:41:22 -08:00
Mike Rodriguez 36b3485ac0 Merge pull request #464 from fanfan42/fanfan1
Correct README and race condition on silent-install.ps1
2026-01-25 11:32:09 -08:00
François Brunhes aka Fanfan e1dd124574 Correct README and race condition on silent-install.ps1 2026-01-24 19:16:59 +01:00
Mike Rodriguez 2b6c91a00f Revert "initial shader work"
This reverts commit 6cead7c2d9.
2026-01-19 05:03:33 -08:00
Joakim Sandström 6cead7c2d9 initial shader work
all code is remarked
2026-01-18 19:47:58 +01:00
Mike Rodriguez 0d59195756 Improve UMDF include path selection and build config
Enhanced the CI workflow to dynamically select the best available UMDF WDF header version on the runner and pass the UMDF version minor to msbuild. Updated MttVDD.vcxproj to include multiple possible UMDF include paths, improving compatibility with different Windows SDK layouts and ensuring the correct headers are used during builds.
2026-01-08 19:13:15 -08:00
Mike Rodriguez 8a83f4fc0d Remove legacy build workflows and update CI
Deleted the 'build-and-sign-sequential.yml' and 'build-installer.yml' workflows, consolidating build logic. Updated 'ci-validation.yml' to 'Build Virtual Display Driver', now building both x64 and ARM64 VDD in matrix jobs and uploading artifacts, streamlining CI for pull requests and manual runs.
2026-01-08 18:16:32 -08:00
Mike Rodriguez 2fa9d67a65 Remove WDF include directory from project file
Eliminated the reference to the Windows-Driver-Frameworks UMDF 2.15 include directory from all build configurations in MttVDD.vcxproj. This streamlines the include paths and may reflect a change in dependency management or project requirements.
2026-01-08 17:57:44 -08:00
Mike Rodriguez 09d5e393f1 Add IddCx header location debug step to CI workflows
Introduces a PowerShell step in both build-and-sign-sequential and ci-validation workflows to output and verify the location of the IddCx header in the Windows SDK. This aids in diagnosing SDK path issues during CI runs.
2026-01-08 17:28:15 -08:00
Mike Rodriguez 54ee545b43 Update IddCx include path and header casing
Changed the include directive from 'iddcx.h' to 'IddCx.h' in Driver.h to match correct casing. Updated MttVDD.vcxproj to add the Windows SDK IddCx include directory, ensuring the correct versioned path is used for IddCx headers.
2026-01-08 17:24:53 -08:00
Mike Rodriguez eaf7e2163f Add Windows Driver Kit installation to CI workflows
Both build-and-sign-sequential.yml and ci-validation.yml now install the Windows Driver Kit using Chocolatey to provide IddCx headers required for the build process.
2026-01-08 17:12:31 -08:00
Mike Rodriguez c622700ff4 Add UMDF 2.15 WDF headers and improve Windows SDK detection
Added Windows Driver Frameworks (WDF) UMDF 2.15 public headers to ThirdParty/Windows-Driver-Frameworks. Updated GitHub Actions workflows to robustly detect and set Windows SDK paths and versions, and to pass these as MSBuild parameters for driver builds. This improves build reliability and ensures correct SDK usage in CI environments.
2026-01-08 17:05:32 -08:00
Mike Rodriguez 12ceed1b3f Vendor UMDF header and update CI workflows
Added Windows Driver Frameworks UMDF header (wudfwdm.h) under ThirdParty to ensure CI builds work on runners missing Windows Kits/WDK. Removed PowerShell logic from CI workflows that attempted to locate or install UMDF headers, and updated MSBuild invocations to no longer depend on custom environment variables for SDK paths.
2026-01-08 16:34:39 -08:00
Mike Rodriguez ea8c879e5c Improve WDK header detection in CI workflows
Update PowerShell logic in build-and-sign-sequential.yml and ci-validation.yml to handle both flat and versioned WDK header layouts. This ensures compatibility with different runner environments by checking for headers in both possible locations.
2026-01-08 16:22:52 -08:00
Mike Rodriguez fe157ea685 Improve UMDF header detection in CI workflows
Refactored PowerShell logic in build-and-sign-sequential.yml and ci-validation.yml to robustly detect and install UMDF headers (wudfwdm.h). Now attempts installation via winget if headers are missing, improving reliability on runners without preinstalled SDK/WDK.
2026-01-08 16:16:45 -08:00
Mike Rodriguez e3924aeb5e Detect and use correct Windows SDK version in CI builds
Added steps to both build-and-sign-sequential.yml and ci-validation.yml workflows to dynamically detect the installed Windows Kits version and set the appropriate MSBuild properties for WindowsSdkDir and WindowsTargetPlatformVersion. This ensures the correct SDK is used for driver builds, improving reliability across environments. Also simplified the SignPath submission step condition.
2026-01-08 16:09:11 -08:00
Mike Rodriguez 0a31eaaacf Refactor and add CI workflows for build and validation
Refactored the build-and-sign-sequential workflow to simplify Windows SDK/WDK installation, update MSBuild setup, and improve installer build steps. Added new workflows: build-installer.yml for building the installer independently, and ci-validation.yml for fast CI validation on PRs and pushes. These changes streamline CI processes and separate installer and validation logic for better maintainability.
2026-01-08 15:55:18 -08:00
Mike Rodriguez 38b6e5117b Update build-and-sign-sequential.yml 2026-01-08 14:17:18 -08:00
Mike Rodriguez 642ee285ff Improve Windows Kits detection and project includes
Added automatic detection of Windows Kits version and SDK directory in the build workflow, passing them to msbuild for driver builds. Removed manual inclusion of wudfwdm.h from the project files to rely on SDK headers, streamlining build configuration and reducing local dependencies.
2026-01-08 14:01:46 -08:00
Mike Rodriguez 7290cd6d87 README: add recent changelog (last 5 feature updates) 2026-01-08 12:59:01 -08:00
Mike Rodriguez fea4d9e4e5 Adapter selection: use explicit DEVPKEY_Device_Luid definition 2026-01-08 12:43:45 -08:00
Mike Rodriguez 13d382731d Build: use C++17 in Release configs 2026-01-08 12:43:09 -08:00
Mike Rodriguez b654504edf Link setupapi.lib (required for PCI bus LUID resolution) 2026-01-08 12:36:47 -08:00
Mike Rodriguez cac37672da Adapter selection: allow LUID resolution by PCI bus 2026-01-08 12:30:17 -08:00
Mike Rodriguez 498c37b30d Fix newline at EOF in Community Scripts README 2026-01-08 12:11:53 -08:00
Joakim Sandström 4bdebe23f2 Merge pull request #442 from Efreak/master
Format community scripts readme to add links and make it readable in github.
2025-11-26 23:18:52 +01:00
efreak 472b2f2a32 Add links to the scripts
Links are referenced at bottom to keep raw text readable.
2025-11-17 14:31:31 -08:00
efreak 3e8d2115c0 Make a table for scripts for readability
On github website, single line-breaks are ignored, causing the list to turn into a paragraph.
This makes it more readable both in the browser and as raw text by aligning the descriptions and making it a table in the browser.
2025-11-17 14:17:26 -08:00
Mike Rodriguez 63f9285461 Revert "Merge pull request #413 from zjoasan/zjoasan-adapteroption-patch1"
This reverts commit 05ae18d104, reversing
changes made to 06b2dbd7d4.
2025-11-09 05:00:51 -08:00
Mike Rodriguez b642ef64d8 Merge pull request #430 from Harinath1314-tech/master
Add VDD Toggle Utility - Batch script for easy enable/disable
2025-10-29 11:27:52 -07:00
Mike Rodriguez 7267835157 Merge pull request #426 from fanfan42/fanfan1
Change devcon to nefcon for silent install community script
2025-10-29 11:26:39 -07:00
Mike Rodriguez 05ae18d104 Merge pull request #413 from zjoasan/zjoasan-adapteroption-patch1
DeviceID, pcislot friendly name
2025-10-29 11:25:54 -07:00
Harinath1314-tech fd8700f636 Create README.md
Add VDD Toggle Utility - Batch script for toggling Virtual Display Driver
2025-10-28 12:53:00 +05:30
François Brunhes aka Fanfan 88916eca0a Change devcon to nefcon for silent install community script 2025-10-17 21:25:14 +02:00
Mike Rodriguez 06b2dbd7d4 Merge pull request #419 from fanfan42/fanfan1
The silent install script is really silent
2025-09-27 15:39:50 -07:00
François Brunhes aka Fanfan 830de3f2aa The silent install script is really silent 2025-09-27 23:32:50 +02:00
Joakim Sandström 7233822630 Update README.md
Added some links to Wiki and Community scripts, and referring to default location for vdd_settings.xml
2025-09-27 17:48:36 +02:00
Mike Rodriguez bccc901b1b Merge pull request #410 from goodusername123/README-table
README.md: Replace table image with actual table
2025-09-08 22:33:29 -07:00
Joakim Sandström 2a18a0b594 DeviceID, pcislot friendly anme
This is untested but "should work" logical code for a first implementation of "dual identical adapter cards"
2025-09-08 19:32:35 +02:00
goodusername123 7becdd43c0 README.md: Replace table image with real table 2025-08-27 04:27:29 -05:00
Mike Rodriguez 3917232ae1 Update build-and-sign-sequential.yml 2025-08-17 17:24:23 -07:00
Mike Rodriguez b5383e859d Update build-and-sign-sequential.yml 2025-08-17 16:59:29 -07:00
Mike Rodriguez 93c6fff4f5 Update build-and-sign-sequential.yml 2025-08-17 16:47:25 -07:00
Mike Rodriguez 74477f745d Update build-and-sign-sequential.yml 2025-08-17 16:10:22 -07:00
Mike Rodriguez d0f8a028c6 Update build-and-sign-sequential.yml 2025-08-17 15:58:21 -07:00
Mike Rodriguez c585ee93cf Build Sequential 2025-08-17 15:49:59 -07:00
Mike Rodriguez b9acacd40c Update build-and-sign-sequential.yml 2025-08-17 15:24:18 -07:00
Mike Rodriguez 0cccd7a14d YML Additions 2025-08-17 14:53:21 -07:00
Mike Rodriguez 89b7b4477d Update build-and-sign-sequential.yml 2025-08-17 14:46:07 -07:00
Mike Rodriguez a01ecfd460 Update build-and-sign-sequential.yml 2025-08-17 14:22:35 -07:00
Mike Rodriguez 587f99c8c3 Update build-and-sign-sequential.yml 2025-08-17 14:01:26 -07:00
Mike Rodriguez dd198e508e Update build-and-sign-sequential.yml 2025-08-17 13:54:05 -07:00
Mike Rodriguez 4b6ba2246e Update version.xml 2025-08-17 08:52:01 -07:00
Mike Rodriguez c928fa9251 Added GettIddCx Source 2025-08-17 04:46:18 -07:00
Mike Rodriguez d5a4466425 Update vdd_settings.xml 2025-08-17 04:44:54 -07:00
Mike Rodriguez a602844e89 Added version.xml for app integration. 2025-08-16 03:02:16 -07:00
Mike Rodriguez 92203a544c EDID Integration
🔌 EDID Profile Integration

  - Automatic Monitor Configuration: Loads settings from monitor_profile.xml
  - Priority System: Manual settings override EDID when needed
  - Graceful Fallback: Uses manual config if EDID loading fails

  🌈 HDR10 Support

  - SMPTE ST.2086 Compliance: Industry-standard HDR metadata
  - Color Primaries: RGB chromaticity coordinates + white point
  - Luminance Management: Min/max mastering + content light levels

  🎨 Advanced Color Processing

  - Multi Color Space: sRGB, DCI-P3, Rec.2020, Adobe RGB support
  - Gamma Correction: Customizable gamma curves with 3x4 matrix transforms
  - FP16 Pipeline: High-precision color calculations

  📺 Intelligent Mode Management

  - EDID Mode Generation: Automatic resolution extraction from profiles
  - Advanced Filtering: Refresh rate, resolution, and aspect ratio constraints
  - Mode Optimization: Duplicate removal and performance tuning

  🛡️ Production Quality

  - Comprehensive Validation: 4-test diagnostic suite with real-time monitoring
  - Configuration Sanitization: Automatic correction of invalid settings
  - Emergency Fallback: sRGB/D65 defaults for system stability
  - Performance Monitoring: 10ms threshold tracking for optimal performance

  🔧 File Structure

  C:\VirtualDisplayDriver\
  ├── vdd_settings.xml          (Required - Main configuration)
  └── EDID\monitor_profile.xml  (Optional - EDID profile data)

  🙏 Acknowledgments

  - MikeTheTech - For implementing this comprehensive EDID integration into the driver codebase.
  - Jocke - For developing the EDID parser that generates the monitor profile data used by this system.
2025-08-14 15:36:09 -07:00
Mike Rodriguez 61ae3fbd07 Merge pull request #400 from tanakamasayuki/patch-1
Update URL
2025-08-13 23:06:49 -07:00
Mike Rodriguez 3750c5ed4f Performance Optimization
Thread Management

  - Added: Explicit thread completion waiting in IndirectDeviceContext::AssignSwapChain()
  - Fixed: SwapChainProcessor destructor race conditions
  - Improved: Thread lifecycle logging and diagnostics

  Resource Management

  - Changed: Device cache from std::map<LUID, std::weak_ptr<Direct3DDevice>> to std::map<LUID,
  std::shared_ptr<Direct3DDevice>>
  - Added: Comprehensive LUID-based logging for device cache operations
  - Optimized: Cleanup frequency reduced from every assignment to every 10th assignment

  Error Handling

  - Implemented: 5-attempt retry limit with exponential backoff for DXGI_ERROR_ACCESS_LOST
  - Added: Device integrity validation before swap chain operations
  - Enhanced: Error logging with detailed HRESULT codes and context
2025-08-13 08:49:45 -07:00
TANAKA Masayuki 506791639d Update URL
https://github.com/VirtualDisplay/
404
2025-08-06 13:36:55 +09:00
Mike Rodriguez 14d1e344d7 Update README.md 2025-07-28 20:57:28 -07:00
Mike Rodriguez d437ebc9b4 Merge pull request #391 from VirtualDrivers/PS-Get_Disp_Num-update
Added a pause for VDC execution
2025-07-23 08:16:43 -07:00
Joakim Sandström 5aa453b3c0 Added a pause for VDC execution
Documented the script a bit, removed non essential header and added "Press any key..."-pause for VDC execution, . 
Now you get a clear screen, example 8:
 \\.\DISPLAY8 
Press any key to continue ...
2025-07-18 11:36:56 +02:00
Mike Rodriguez 0a095d4b76 Delete .github/workflows/build-fix.ps1 2025-07-14 16:50:28 -07:00
Mike Rodriguez 8e874f0bed Delete .github/workflows/compile.yml 2025-07-14 16:50:02 -07:00
Mike Rodriguez 33ea391a91 Delete .github/workflows/build-and-sign-all.yml 2025-07-14 16:49:47 -07:00
Mike Rodriguez 5b9822bc0b Delete .github/workflows/SubmitAllToSignPath 2025-07-14 16:49:36 -07:00
Mike Rodriguez 8c9b0f8c9a Delete .github/workflows/Submit-To-SignPath.yml 2025-07-14 16:49:24 -07:00
Mike Rodriguez 0969263ba1 Update build-and-sign-sequential.yml 2025-07-14 16:15:06 -07:00
Mike Rodriguez d4964dbcfd Add files via upload 2025-07-14 15:48:17 -07:00
Mike Rodriguez 25eb449ee6 Update build-and-sign-all.yml 2025-07-14 15:36:00 -07:00
Mike Rodriguez 05f279346f Update build-and-sign-all.yml 2025-07-14 15:07:17 -07:00
Mike Rodriguez 9e8f62ab3c Update build-and-sign-all.yml 2025-07-14 14:43:19 -07:00
Mike Rodriguez ac0c52e8a5 Update build-and-sign-all.yml 2025-07-14 14:12:43 -07:00
Mike Rodriguez 0f2c9106be Update build-and-sign-all.yml 2025-07-14 14:05:33 -07:00
Mike Rodriguez 724bec4115 Update build-and-sign-all.yml 2025-07-14 13:52:06 -07:00
Mike Rodriguez 8e76e9dc14 Update build-and-sign-all.yml 2025-07-14 13:41:58 -07:00
Mike Rodriguez b8a6fe0fb8 Add files via upload 2025-07-14 13:34:59 -07:00
Mike Rodriguez 3650e70d02 Merge pull request #379 from PanicTitan/master
New script to manager the virtual driver in cli
2025-06-17 05:11:12 -07:00
Mike Rodriguez 24c740857a Merge pull request #367 from zjoasan/patch-1
Update scripts README.md
2025-06-17 05:10:50 -07:00
PanicTitan e851bf9a3b Create virtual-driver-manager.ps1
A script to install, uninstall, enable, disable, toggle, and check the status of the driver. Based on current Community Scripts with Silent options and json outs for use in other programs,
2025-06-17 00:47:56 -03:00
Mike Rodriguez b49fc4017e Remove VAD workflows temporarily. 2025-05-15 23:27:04 -07:00
Mike Rodriguez 1dde89134f Worflows 2025-05-15 23:14:50 -07:00
Mike Rodriguez c53bd3f66b Update VAD-compile-and-sign.yml 2025-05-15 22:22:44 -07:00
Mike Rodriguez 8ea77f7f06 Update VAD-compile-and-sign.yml 2025-05-15 22:02:26 -07:00
Mike Rodriguez 646c2d833f Update VAD-compile-and-sign.yml 2025-05-15 21:38:26 -07:00
Mike Rodriguez e19d8a82b9 Oops 2025-05-15 21:21:17 -07:00
Mike Rodriguez d4f2eba005 .CAT signing adjustments. 2025-05-15 21:01:02 -07:00
Mike Rodriguez 54d3113196 Fixed $packageDir 2025-05-15 19:54:44 -07:00
Mike Rodriguez 03b08e474f Ignore restart required. 2025-05-15 19:34:58 -07:00
Mike Rodriguez 9eeb8fec55 Added VAD for building. 2025-05-15 18:46:51 -07:00
Mike Rodriguez 56a78f9214 Update README.md 2025-05-08 02:35:22 -07:00
Mike Rodriguez dd1fa14bc9 Update README.md 2025-05-08 02:31:51 -07:00
Mike Rodriguez 36461d5022 Update README.md 2025-05-08 02:30:15 -07:00
Mike Rodriguez d7a0d3ec33 Update workflow. 2025-05-08 02:11:45 -07:00
Mike Rodriguez 0b8f896008 Workflow update/test. 2025-05-08 01:24:27 -07:00
Joakim Sandström aaa12df16d Update README.md
Added a short description for most scripts.
2025-05-06 11:57:41 +02:00
Mike Rodriguez cae46b429d Update MttVDD.vcxproj 2025-05-02 23:56:31 -07:00
Mike Rodriguez 1995e6de2b Revert "Test"
This reverts commit c6b1e893ec.
2025-05-02 23:42:58 -07:00
Mike Rodriguez c6b1e893ec Test 2025-05-02 23:41:42 -07:00
79 changed files with 22624 additions and 760 deletions

No files matched your search

+26
View File
@@ -0,0 +1,26 @@
---
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
rebase-strategy: disabled
schedule:
interval: "cron"
cronjob: "0 2 * * *"
timezone: "America/New_York"
open-pull-requests-limit: 10
groups:
github-actions:
applies-to: version-updates
patterns:
- "actions/*"
- "github/*"
- package-ecosystem: "gitsubmodule"
directory: "/"
rebase-strategy: disabled
schedule:
interval: "cron"
cronjob: "30 2 * * *"
timezone: "America/New_York"
open-pull-requests-limit: 10
-141
View File
@@ -1,141 +0,0 @@
name: Virtual Display Driver Signpath Request
on:
workflow_dispatch:
jobs:
build:
runs-on: windows-latest
strategy:
matrix:
configuration: [Release]
platform: [x64, ARM64]
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v1
- name: Check Chocolatey installation
run: choco --version
- name: Install Visual Studio 2022 dependencies
run: |
choco install visualstudio2022-workload-manageddesktop -y
if ($LASTEXITCODE -ne 0) { exit 1 }
choco install visualstudio2022-workload-nativedesktop -y
if ($LASTEXITCODE -ne 0) { exit 1 }
choco install visualstudio2022-workload-vctools -y
if ($LASTEXITCODE -ne 0) { exit 1 }
choco install windowsdriverkit11 -y
if ($LASTEXITCODE -ne 0) { exit 1 }
- name: Build the driver
run: |
msbuild "Virtual Display Driver (HDR)/MTTVDD.sln" /p:Configuration=${{ matrix.configuration }} /p:Platform=${{ matrix.platform }}
- name: List build directory
run: dir "Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD"
- name: Upload built driver
id: upload_artifact
uses: actions/upload-artifact@v4
with:
name: Built-Driver-${{ matrix.configuration }}-${{ matrix.platform }}
path: |
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\MttVDD.dll
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\MttVDD.inf
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\mttvdd.cat
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\vdd_settings.xml
- name: Generate release tag
id: generate_tag
run: |
$releaseTag = (Get-Date).ToString('yy.MM.dd')
echo "RELEASE_TAG=$releaseTag" >> $env:GITHUB_ENV
- name: Show generated release tag
run: |
echo "Generated Release Tag: ${{ env.RELEASE_TAG }}"
- name: Verify Built Artifacts
run: dir 'Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD'
- name: Submit signing request to SignPath
id: signpath_request
uses: signpath/github-action-submit-signing-request@v1
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: '${{ vars.SIGNPATH_ORG_ID }}'
project-slug: '${{ vars.SIGNPATH_PROJECT_SLUG }}'
signing-policy-slug: '${{ vars.SIGNPATH_POLICY_SLUG }}'
github-artifact-id: '${{ steps.upload_artifact.outputs.artifact-id }}'
wait-for-completion: true
output-artifact-directory: '${{ vars.SIGNPATH_OUTPUT_DIR }}'
parameters: |
Version: ${{ toJSON(matrix.configuration) }}
Release_Tag: "${{ env.RELEASE_TAG }}"
- name: Verify Signed Artifacts
run: dir '${{ vars.SIGNPATH_OUTPUT_DIR }}'
- name: Upload signed artifacts
id: upload_signed_artifacts
uses: actions/upload-artifact@v4
with:
name: Signed-Driver-${{ matrix.configuration }}-${{ matrix.platform }}
path: |
${{ vars.SIGNPATH_OUTPUT_DIR }}\MttVDD.dll
${{ vars.SIGNPATH_OUTPUT_DIR }}\MttVDD.inf
${{ vars.SIGNPATH_OUTPUT_DIR }}\mttvdd.cat
${{ vars.SIGNPATH_OUTPUT_DIR }}\vdd_settings.xml
- name: Prepare Setup Repository
run: |
git clone https://${{ secrets.READ_REPO }}@github.com/VirtualDisplay/Virtual-Driver-Installer.git inno-setup
- name: Prepare Setup
run: |
copy "${{ vars.SIGNPATH_OUTPUT_DIR }}\*" inno-setup\input\
$platform = "${{ matrix.platform }}"
(Get-Content "inno-setup\Setup.iss") |
ForEach-Object { $_ -replace '1.0.0', '${{ env.RELEASE_TAG }}' } |
Set-Content "inno-setup\Setup.iss"
if ($platform -eq 'ARM64') {
(Get-Content "inno-setup\Setup.iss") |
ForEach-Object { $_ -replace 'x64compatible', 'arm64' } |
Set-Content "inno-setup\Setup.iss"
(Get-Content "inno-setup\Setup.iss") |
ForEach-Object { $_ -replace '-x64', '-arm64' } |
Set-Content "inno-setup\Setup.iss"
if (Test-Path "inno-setup\input\Companion\VDDSysTray.exe") {Remove-Item "inno-setup\input\Companion\VDDSysTray.exe"}
copy "inno-setup\input\Companion\arm64\VDDSysTray.exe" "inno-setup\input\Companion\"
}
- name: Compile Installer
uses: Minionguyjpro/Inno-Setup-Action@v1.2.2
with:
path: inno-setup\Setup.iss
options: /O+
- name: Upload Installer as artifact
uses: actions/upload-artifact@v4
with:
name: Installer-${{ matrix.configuration }}-${{ matrix.platform }}
path: inno-setup\output\*.exe
celebrate:
runs-on: ubuntu-latest
steps:
- name: Celebrate
run: |
echo "Bud is a god, also hi if you're looking at this!"
-157
View File
@@ -1,157 +0,0 @@
name: Virtual Display Driver All Signpath Request
on:
workflow_dispatch:
jobs:
build:
runs-on: windows-latest
strategy:
matrix:
configuration: [Release]
platform: [x64, ARM64]
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v1
- name: Check Chocolatey installation
run: choco --version
- name: Install Visual Studio 2022 dependencies
run: |
choco install visualstudio2022-workload-manageddesktop -y
if ($LASTEXITCODE -ne 0) { exit 1 }
choco install visualstudio2022-workload-nativedesktop -y
if ($LASTEXITCODE -ne 0) { exit 1 }
choco install visualstudio2022-workload-vctools -y
if ($LASTEXITCODE -ne 0) { exit 1 }
choco install windowsdriverkit11 -y
if ($LASTEXITCODE -ne 0) { exit 1 }
- name: Build the driver
run: |
msbuild "Virtual Display Driver (HDR)/MTTVDD.sln" /p:Configuration=${{ matrix.configuration }} /p:Platform=${{ matrix.platform }}
- name: List build directory
run: dir "Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD"
- name: Upload built driver
id: upload_artifact
uses: actions/upload-artifact@v4
with:
name: Built-Driver-${{ matrix.configuration }}-${{ matrix.platform }}
path: |
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\MttVDD.dll
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\MttVDD.inf
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\mttvdd.cat
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\vdd_settings.xml
- name: Generate release tag
id: generate_tag
run: |
$releaseTag = (Get-Date).ToString('yy.MM.dd')
echo "RELEASE_TAG=$releaseTag" >> $env:GITHUB_ENV
- name: Show generated release tag
run: |
echo "Generated Release Tag: ${{ env.RELEASE_TAG }}"
- name: Verify Built Artifacts
run: dir 'Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD'
- name: Submit signing request to SignPath
id: signpath_request
uses: signpath/github-action-submit-signing-request@v1
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: '${{ vars.SIGNPATH_ORG_ID }}'
project-slug: '${{ vars.SIGNPATH_PROJECT_SLUG }}'
signing-policy-slug: '${{ vars.SIGNPATH_POLICY_SLUG }}'
github-artifact-id: '${{ steps.upload_artifact.outputs.artifact-id }}'
wait-for-completion: true
output-artifact-directory: '${{ vars.SIGNPATH_OUTPUT_DIR }}'
parameters: |
Version: ${{ toJSON(matrix.configuration) }}
Release_Tag: "${{ env.RELEASE_TAG }}"
- name: Verify Signed Artifacts
run: dir '${{ vars.SIGNPATH_OUTPUT_DIR }}'
- name: Upload signed artifacts
id: upload_signed_artifacts
uses: actions/upload-artifact@v4
with:
name: Signed-Driver-${{ matrix.configuration }}-${{ matrix.platform }}
path: |
${{ vars.SIGNPATH_OUTPUT_DIR }}\MttVDD.dll
${{ vars.SIGNPATH_OUTPUT_DIR }}\MttVDD.inf
${{ vars.SIGNPATH_OUTPUT_DIR }}\mttvdd.cat
${{ vars.SIGNPATH_OUTPUT_DIR }}\vdd_settings.xml
- name: Prepare Setup Repository
run: |
git clone https://${{ secrets.READ_REPO }}@github.com/VirtualDisplay/Virtual-Driver-Installer.git inno-setup
- name: Prepare Setup
run: |
copy "${{ vars.SIGNPATH_OUTPUT_DIR }}\*" inno-setup\input\
$platform = "${{ matrix.platform }}"
(Get-Content "inno-setup\Setup.iss") |
ForEach-Object { $_ -replace '1.0.0', '${{ env.RELEASE_TAG }}' } |
Set-Content "inno-setup\Setup.iss"
if ($platform -eq 'ARM64') {
(Get-Content "inno-setup\Setup.iss") |
ForEach-Object { $_ -replace 'x64compatible', 'arm64' } |
Set-Content "inno-setup\Setup.iss"
(Get-Content "inno-setup\Setup.iss") |
ForEach-Object { $_ -replace '-x64', '-arm64' } |
Set-Content "inno-setup\Setup.iss"
if (Test-Path "inno-setup\input\Companion\VDDSysTray.exe") {Remove-Item "inno-setup\input\Companion\VDDSysTray.exe"}
copy "inno-setup\input\Companion\arm64\VDDSysTray.exe" "inno-setup\input\Companion\"
}
- name: Compile Installer
uses: Minionguyjpro/Inno-Setup-Action@v1.2.2
with:
path: inno-setup\Setup.iss
options: /O+
- name: Upload Installer as artifact
uses: actions/upload-artifact@v4
with:
name: Installer-${{ matrix.configuration }}-${{ matrix.platform }}
path: inno-setup\output\*.exe
- name: Submit Installer Signing Request to SignPath
id: signpath_installer_request
uses: signpath/github-action-submit-signing-request@v1
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: '${{ vars.SIGNPATH_ORG_ID }}'
project-slug: '${{ vars.SIGNPATH_PROJECT_SLUG }}'
signing-policy-slug: '${{ vars.SIGNPATH_POLICY_SLUG_INSTALLER }}'
github-artifact-id: '${{ steps.upload_installer.outputs.artifact-id }}'
wait-for-completion: true
output-artifact-directory: '${{ vars.SIGNPATH_INSTALLER_OUTPUT_DIR }}'
- name: Upload signed installer
uses: actions/upload-artifact@v4
with:
name: Signed-Installer-${{ matrix.configuration }}-${{ matrix.platform }}
path: '${{ vars.SIGNPATH_INSTALLER_OUTPUT_DIR }}/*'
celebrate:
runs-on: ubuntu-latest
steps:
- name: Celebrate
run: |
echo "Bud is a god, also hi if you're looking at this!"
+150
View File
@@ -0,0 +1,150 @@
---
name: Build Virtual Display Driver
on:
pull_request:
push:
branches: [ main, master ]
paths-ignore:
- '**.md'
- 'docs/**'
- 'LICENSE*'
workflow_dispatch:
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true
env:
BUILD_CONFIGURATION: Release
VDD_SOLUTION: Virtual Display Driver (HDR)/MttVDD.sln
permissions:
contents: read
jobs:
build:
# The WDK driver build is validated against VS 2022; windows-latest is moving to VS 2026.
runs-on: windows-2022
strategy:
fail-fast: false
matrix:
platform: [x64, ARM64]
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
submodules: true
- name: Setup MSBuild
uses: microsoft/setup-msbuild@30375c66a4eea26614e0d39710365f22f8b0af57 # v3.0.0
- name: Install Windows Driver Kit (IddCx headers)
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
choco install windowsdriverkit11 -y --no-progress
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- name: Detect Windows SDK (windows.h)
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
$kitsRoot = $null
try {
$kitsRoot = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots" -Name "KitsRoot10" -ErrorAction Stop).KitsRoot10
} catch {
$kitsRoot = Join-Path ${env:ProgramFiles(x86)} "Windows Kits\10\"
}
if (-not $kitsRoot -or -not (Test-Path $kitsRoot)) {
throw "Windows Kits root not found: $kitsRoot"
}
$includeRoot = Join-Path $kitsRoot "Include"
if (-not (Test-Path $includeRoot)) {
throw "Windows Kits Include directory not found: $includeRoot"
}
$best =
Get-ChildItem -Path $includeRoot -Directory -ErrorAction SilentlyContinue |
Where-Object { $_.Name -match '^\d+\.\d+\.\d+\.\d+$' } |
Where-Object { Test-Path (Join-Path $_.FullName "um\Windows.h") } |
Sort-Object -Property Name -Descending |
Select-Object -First 1
if (-not $best) {
throw "Could not find an SDK version directory containing um\\Windows.h under: $includeRoot"
}
$sdkVersion = $best.Name
Write-Output "Using WindowsSdkDir: $kitsRoot"
Write-Output "Using WindowsTargetPlatformVersion: $sdkVersion"
"WINDOWS_SDK_DIR=$kitsRoot" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
"WINDOWS_TARGET_PLATFORM_VERSION=$sdkVersion" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
- name: Build VDD (${{ matrix.platform }})
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
$sln = "${{ env.VDD_SOLUTION }}"
if (-not (Test-Path $sln)) { throw "VDD solution file not found at: $sln" }
# Pick an available UMDF WDF header version on the runner.
# Kits can be laid out either versioned:
# Include\<sdk>\wdf\umdf\2.xx
# or unversioned:
# Include\wdf\umdf\2.xx
$umdfRoots = @(
(Join-Path $env:WINDOWS_SDK_DIR ("Include\" + $env:WINDOWS_TARGET_PLATFORM_VERSION + "\wdf\umdf")),
(Join-Path $env:WINDOWS_SDK_DIR "Include\wdf\umdf")
) | Where-Object { Test-Path $_ }
if (-not $umdfRoots -or $umdfRoots.Count -eq 0) {
throw "UMDF WDF include root not found under $env:WINDOWS_SDK_DIR (tried versioned + unversioned layouts)"
}
$umdfBest =
$umdfRoots |
ForEach-Object { Get-ChildItem -Path $_ -Directory -ErrorAction SilentlyContinue } |
Where-Object { $_.Name -match '^\d+\.\d+$' } |
Sort-Object -Property Name -Descending |
Select-Object -First 1
if (-not $umdfBest) { throw "No UMDF version directories found under: $($umdfRoots -join ', ')" }
$umdfMinor = ($umdfBest.Name -split '\.')[1]
Write-Output "Using UMDF version: $($umdfBest.Name) (minor=$umdfMinor) from $($umdfBest.FullName)"
msbuild $sln `
/m `
/t:Build `
/p:Configuration="${{ env.BUILD_CONFIGURATION }}" `
/p:Platform="${{ matrix.platform }}" `
/p:WindowsSdkDir="$env:WINDOWS_SDK_DIR" `
/p:WindowsTargetPlatformVersion="$env:WINDOWS_TARGET_PLATFORM_VERSION" `
/p:UMDF_VERSION_MINOR="$umdfMinor" `
/p:EnableInfVerif=false `
/p:RunApiValidator=false `
/verbosity:minimal
- name: Collect outputs
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
$outDir = "Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ env.BUILD_CONFIGURATION }}\MttVDD"
if (-not (Test-Path $outDir)) { throw "Build output directory not found: $outDir" }
$dest = "artifacts\VDD\${{ matrix.platform }}"
New-Item -ItemType Directory -Path $dest -Force | Out-Null
Copy-Item "$outDir\*" -Destination $dest -Recurse -Force
- name: Upload artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: VDD-${{ matrix.platform }}-${{ env.BUILD_CONFIGURATION }}
path: artifacts/VDD/${{ matrix.platform }}/
if-no-files-found: error
-143
View File
@@ -1,143 +0,0 @@
name: Virtual Display Driver Building
on:
workflow_dispatch:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: windows-latest
strategy:
matrix:
configuration: [Debug, Release]
platform: [x64, ARM64]
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v1
- name: Check Chocolatey installation
run: choco --version
- name: Install Visual Studio 2022 dependencies
run: |
choco install visualstudio2022-workload-manageddesktop -y
if ($LASTEXITCODE -ne 0) { exit 1 }
choco install visualstudio2022-workload-nativedesktop -y
if ($LASTEXITCODE -ne 0) { exit 1 }
choco install visualstudio2022-workload-vctools -y
if ($LASTEXITCODE -ne 0) { exit 1 }
choco install windowsdriverkit11 -y
if ($LASTEXITCODE -ne 0) { exit 1 }
# Fix the string conversion warning treated as error
- name: Fix string conversion in Driver.cpp
run: |
$filePath = "Virtual Display Driver (HDR)/MttVDD/Driver.cpp"
$content = Get-Content -Path $filePath -Raw
$content = $content -replace 'string edidPath\(edidname\.begin\(\), edidname\.end\(\)\);', 'string edidPath = WStringToString(edidname);'
Set-Content -Path $filePath -Value $content
# Fix the missing InfVerif.dll issue
- name: Fix WDK paths for InfVerif
run: |
# Find where infverif.dll actually exists in the WDK installation
Write-Host "Searching for infverif.dll..."
Get-ChildItem -Path "C:\Program Files (x86)\Windows Kits\10" -Recurse -Filter "infverif.dll" -ErrorAction SilentlyContinue | Select-Object FullName
# Check both potential WDK versions
$wdkPaths = @(
"C:\Program Files (x86)\Windows Kits\10\bin\10.0.22000.0",
"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0"
)
foreach ($basePath in $wdkPaths) {
Write-Host "Checking $basePath..."
if (Test-Path "$basePath\x86") {
# Create the subfolder if it doesn't exist
if (-not (Test-Path "$basePath\x86\x86")) {
New-Item -Path "$basePath\x86\x86" -ItemType Directory -Force
Write-Host "Created directory: $basePath\x86\x86"
}
# Copy files if they exist
if (Test-Path "$basePath\x86\infverif.dll") {
Copy-Item "$basePath\x86\infverif.dll" "$basePath\x86\x86\" -Force
Write-Host "Copied infverif.dll to $basePath\x86\x86\"
} elseif (Test-Path "$basePath\x86\InfVerif.exe") {
# Sometimes it's an exe instead of dll
Copy-Item "$basePath\x86\InfVerif.exe" "$basePath\x86\x86\" -Force
Write-Host "Copied InfVerif.exe to $basePath\x86\x86\"
}
# List contents to verify
Write-Host "Contents of $basePath\x86\x86:"
Get-ChildItem "$basePath\x86\x86" -ErrorAction SilentlyContinue
}
}
# Try another approach - check if we need to extract infverif.dll from somewhere
Write-Host "Checking for InfVerif.exe..."
$infVerifExe = Get-ChildItem -Path "C:\Program Files (x86)\Windows Kits\10" -Recurse -Filter "InfVerif.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName
if ($infVerifExe) {
Write-Host "Found InfVerif.exe at: $infVerifExe"
$exeDir = Split-Path -Parent $infVerifExe
$targetDir = "$exeDir\x86"
# Create directory if needed
if (-not (Test-Path $targetDir)) {
New-Item -Path $targetDir -ItemType Directory -Force
Write-Host "Created directory: $targetDir"
}
# Create a dummy infverif.dll if needed
if (-not (Test-Path "$targetDir\infverif.dll")) {
# Create empty dll as placeholder (this is a hacky fix but might work)
[System.IO.File]::WriteAllBytes("$targetDir\infverif.dll", [byte[]]@(0x4D, 0x5A))
Write-Host "Created placeholder infverif.dll at: $targetDir\infverif.dll"
}
}
# Print the directory structure to help diagnose
Write-Host "WDK bin directory structure:"
Get-ChildItem "C:\Program Files (x86)\Windows Kits\10\bin" -Recurse -Depth 3 | Where-Object { $_.Name -like "*inf*" -or $_.FullName -like "*\x86\*" }
- name: Build the driver
run: |
msbuild "Virtual Display Driver (HDR)/MTTVDD.sln" /p:Configuration=${{ matrix.configuration }} /p:Platform=${{ matrix.platform }}
- name: List build directory
run: dir "Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD"
- name: Upload built driver
id: upload_artifact
uses: actions/upload-artifact@v4
with:
name: Built-Driver-${{ matrix.configuration }}-${{ matrix.platform }}
path: |
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\MttVDD.dll
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\MttVDD.inf
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\mttvdd.cat
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\vdd_settings.xml
- name: Generate release tag
id: generate_tag
run: |
$releaseTag = (Get-Date).ToString('yy.MM.dd')
echo "RELEASE_TAG=$releaseTag" >> $env:GITHUB_ENV
- name: Show generated release tag
run: |
echo "Generated Release Tag: ${{ env.RELEASE_TAG }}"
- name: Verify Built Artifacts
run: dir 'Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD'
+6
View File
@@ -240,3 +240,9 @@ ModelManifest.xml
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
**/.claude/settings.local.json
CLAUDE.md
+3
View File
@@ -0,0 +1,3 @@
[submodule "ThirdParty/Windows-Driver-Frameworks"]
path = ThirdParty/Windows-Driver-Frameworks
url = https://github.com/microsoft/Windows-Driver-Frameworks.git
+104 -2
View File
@@ -3,10 +3,26 @@
#include <wrl/client.h> // For ComPtr
#include <dxgi.h> // For IDXGIAdapter, IDXGIFactory1
#include <algorithm> // For sort
#include <setupapi.h>
#include <devguid.h>
#include <devpropdef.h>
#include <devpkey.h>
#include <cstdint>
#include <optional>
#include <string>
#include <vector>
#include <fstream>
using namespace std;
using namespace Microsoft::WRL;
// DEVPKEY_Device_Luid: {60b193cb-5276-4d0f-96fc-f173ab17af69}, 2
// Define it ourselves to avoid SDK/WDK header differences where DEVPKEY_Device_Luid may not be declared.
static const DEVPROPKEY DEVPKEY_Device_Luid_Custom = {
{ 0x60b193cb, 0x5276, 0x4d0f, { 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6 } },
2
};
// Structure to vector gpus
struct GPUInfo {
wstring name; // GPU name
@@ -49,6 +65,68 @@ vector<GPUInfo> getAvailableGPUs() {
return gpus;
}
// Resolve an adapter LUID from a PCI bus number by enumerating display devices (SetupAPI).
// Returns nullopt if no match is found or if the system doesn't expose the LUID property.
inline std::optional<LUID> ResolveAdapterLuidFromPciBus(uint32_t targetBusIndex) {
HDEVINFO devInfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, nullptr, nullptr, DIGCF_PRESENT);
if (devInfo == INVALID_HANDLE_VALUE) {
return std::nullopt;
}
SP_DEVINFO_DATA devData = {};
devData.cbSize = sizeof(devData);
std::optional<LUID> result = std::nullopt;
for (DWORD i = 0; SetupDiEnumDeviceInfo(devInfo, i, &devData); ++i) {
DWORD currentBus = 0;
if (!SetupDiGetDeviceRegistryPropertyW(
devInfo,
&devData,
SPDRP_BUSNUMBER,
nullptr,
reinterpret_cast<PBYTE>(&currentBus),
sizeof(currentBus),
nullptr)) {
continue;
}
if (static_cast<uint32_t>(currentBus) != targetBusIndex) {
continue;
}
// DEVPKEY_Device_Luid is exposed as a UINT64 on Windows; convert into LUID.
DEVPROPTYPE propType = 0;
ULONG propSize = 0;
ULONGLONG luid64 = 0;
if (!SetupDiGetDevicePropertyW(
devInfo,
&devData,
&DEVPKEY_Device_Luid_Custom,
&propType,
reinterpret_cast<PBYTE>(&luid64),
sizeof(luid64),
&propSize,
0)) {
continue;
}
if (propType != DEVPROP_TYPE_UINT64 || propSize != sizeof(luid64)) {
continue;
}
LUID luid{};
luid.LowPart = static_cast<DWORD>(luid64 & 0xFFFFFFFFull);
luid.HighPart = static_cast<LONG>((luid64 >> 32) & 0xFFFFFFFFull);
result = luid;
break;
}
SetupDiDestroyDeviceInfoList(devInfo);
return result;
}
class AdapterOption {
public:
bool hasTargetAdapter{}; // Indicates if a target adapter is selected
@@ -110,8 +188,32 @@ public:
}
private:
// Find and set the adapter by its name
bool findAndSetAdapter(const wstring& adapterName) {
// Find and set the adapter by name, optionally using "name,bus" where bus is the PCI bus number.
bool findAndSetAdapter(const wstring& adapterSpec) {
// If user provides "name,bus", use bus to resolve LUID (more deterministic on multi-GPU setups).
const size_t comma = adapterSpec.find(L',');
if (comma != wstring::npos) {
const wstring namePart = adapterSpec.substr(0, comma);
wstring busPart = adapterSpec.substr(comma + 1);
// Trim whitespace in bus part
busPart.erase(remove_if(busPart.begin(), busPart.end(), iswspace), busPart.end());
wchar_t* end = nullptr;
const unsigned long busUl = wcstoul(busPart.c_str(), &end, 10);
const bool parsedOk = (end != nullptr) && (*end == L'\0') && (end != busPart.c_str());
if (parsedOk && busUl <= 0xFFFFFFFFul) {
if (auto luidOpt = ResolveAdapterLuidFromPciBus(static_cast<uint32_t>(busUl)); luidOpt.has_value()) {
adapterLuid = luidOpt.value();
hasTargetAdapter = true;
return true;
}
}
// Fall through to name matching using the name portion.
return findAndSetAdapter(namePart);
}
const wstring& adapterName = adapterSpec;
auto gpus = getAvailableGPUs();
// Iterate through all available GPUs
+18 -7
View File
@@ -1,9 +1,20 @@
#Scripts
# Scripts
This is a collection of Powershell scripts, written during the whole driver development. There haven't been a focus on keeping the scripts "up to date" all the time. Which means changes that might have occurred in the modules that these scripts depend upon, haven't been corrected either.
This is a collection of Powershell scripts, written during the whole driver development. PR's are welcome for improvements or other/more functions. There haven't been a focus on keeping the scripts "up to date" all the time. Which means changes that might have occurred in the modules that these scripts depend upon, haven't been corrected either. These are more ment as a framework for "tinkers" to make use of Powershell to change settings on the fly. To use these, you should be at least be comfortable with Powershell and understand Admin privilegiets, risk/reward.
This is more ment as a framework for "tinkers" to make use of Powershell to change settings on the fly.
To use these, you should be at least be comfortable with Powershell and understand Admin privilegiets, risk/reward.
PR's are welcome for improvements or other/more functions.
Anyway here is a short description of each script:
| Script | Description |
| ---------------------- | ---------------- |
| [changeres‑VDD.ps1](changeres-VDD.ps1) | Hot‑swaps the virtual panel’s resolution to the width and height you pass on the command line. |
| [get_disp_num.ps1](get_disp_num.ps1) | Returns the numeric adapter ID of the VDD screen by scanning WMI for your custom “MTT1337” monitor identifier. |
| [HDRswitch‑VDD.ps1](HDRswitch-VDD.ps1) | Flips the virtual screen between SDR (8‑bit) and HDR (10‑bit) colour modes in one click. Unsure if it works anylonger, since changes in modules |
| [modules_install.bat](modules_install.bat) | Opens an elevated PowerShell session that installs the DisplayConfig and MonitorConfig modules so every helper script has its prerequisites. |
| [primary‑VDD.ps1](primary-VDD.ps1) | Makes the virtual display the Windows primary so you can stream or remote‑desktop from a headless rig. |
| [refreshrate‑VDD.ps1](refreshrate.ps1) | Changes the VDD monitor’s refresh rate (30‑‑500 Hz) after validating the value against a safe list. |
| [rotate‑VDD.ps1](rotate-VDD.ps1) | Rotates the virtual display 90°, 180°, or 270° by calling DisplayConfig with the matching rotation token. |
| [scale‑VDD.ps1](scale-VDD.ps1) | Sets or resets DPI scaling on the virtual monitor, respecting Windows’ maximum allowed scale factor. |
| [set‑dependencies.ps1](set-dependencies.ps1) | Verifies the exact module versions required, installs or imports them on demand, and aborts downstream execution if anything is missing. |
| [silent‑install.ps1](silent-install.ps1) | Silently fetches the latest signed Virtual Display Driver from GitHub and installs it via Nefcon, then tidies up the temp workspace. |
| [toggle‑VDD.ps1](toggle-VDD.ps1) | A one‑click PowerShell switch that first elevates itself to admin, then enables or disables your Virtual Display Driver and immediately flips Windows between Extended and Cloned desktops, perfect for streamers who need to bring a virtual monitor online or offline on demand. |
| [virtual-driver-manager.ps1](virtual-driver-manager.ps1) | A comprehensive script to manage the Virtual Display Driver. It can install, uninstall, enable, disable, toggle, and check the status of the driver. |
| [winp‑VDD.ps1](winp-VDD.ps1) | A lightweight companion script that leaves the driver untouched and simply yo‑yos Windows between Extend and Clone modes, giving you an instant “presentation toggle” when the virtual display should stay permanently enabled. |
+12 -1
View File
@@ -1 +1,12 @@
Get-Monitor | Where-Object { $_.InstanceName -like '*MTT1337*' } | Sort-Object { [int] (($_.InstanceName -match 'UID(\d+)') -and $Matches[1]) } | Select-Object -First 1 -ExpandProperty LogicalDisplay | select-object Devicename
# One-liner to get the logicalname of the first VDD
# You can alter the script -First 3, would make the third in the list,
# or -Last 2 would give second from last.
$dispnum = (Get-Monitor | Where-Object { $_.InstanceName -like '*MTT1337*' } | Sort-Object { [int] (($_.InstanceName -match 'UID(\d+)') -and $Matches[1]) } | Select-Object -First 1).LogicalDisplay.DeviceName
# Echo the result to console
Write-Host $dispnum
# Pause the console from closeing when executed from VDC
Write-Host "Press any key to continue ..."
$host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | Out-Null
+46 -59
View File
@@ -1,70 +1,57 @@
# Run this script in a powershell with administrator rights (run as administrator)
[CmdletBinding()]
param(
# SHA256 hash of the DevCon binary to install
# Possible values can be found at:
# https://github.com/Drawbackz/DevCon-Installer/blob/master/devcon_sources.json
# Look for the "sha256" field in the JSON for valid hash values
[Parameter(Mandatory=$true)]
[string]$DevconHash,
# Latest stable version of VDD
# Latest stable version of NefCon installer
[Parameter(Mandatory=$false)]
[string]$DriverVersion = "latest"
)
[string]$NefConURL = "https://github.com/nefarius/nefcon/releases/download/v1.14.0/nefcon_v1.14.0.zip",
# Latest stable version of VDD driver only
[Parameter(Mandatory=$false)]
[string]$DriverURL = "https://github.com/VirtualDrivers/Virtual-Display-Driver/releases/download/25.7.23/VirtualDisplayDriver-x86.Driver.Only.zip"
);
# Create temp directory
$tempDir = Join-Path $env:TEMP "VDDInstall"
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
$tempDir = Join-Path $env:TEMP "VDDInstall";
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null;
# Download and run DevCon Installer
Write-Host "Installing DevCon..." -ForegroundColor Cyan
$devconPath = Join-Path $tempDir "Devcon.Installer.exe"
Invoke-WebRequest -Uri "https://github.com/Drawbackz/DevCon-Installer/releases/download/1.4-rc/Devcon.Installer.exe" -OutFile $devconPath
Start-Process -FilePath $devconPath -ArgumentList "install -hash $DevconHash -update -dir `"$tempDir`"" -Wait -NoNewWindow
# Download and unzip NefCon
Write-Host "Downloading and extracting NefCon..." -ForegroundColor Cyan;
$NefConZipPath = Join-Path $tempDir "nefcon.zip";
Invoke-WebRequest -Uri $NefConURL -OutFile $NefConZipPath -UseBasicParsing -ErrorAction Stop;
Expand-Archive -Path $NefConZipPath -DestinationPath $tempDir -Force -ErrorAction Stop;
$NefConExe = Join-Path $tempDir "x64\nefconw.exe";
# Define path to devcon executable
$devconExe = Join-Path $tempDir "devcon.exe"
# Download and unzip VDD
Write-Host "Downloading and extracting VDD..." -ForegroundColor Cyan;
$driverZipPath = Join-Path $tempDir 'driver.zip';
Invoke-WebRequest -Uri $DriverURL -OutFile $driverZipPath;
Expand-Archive -Path $driverZipPath -DestinationPath $tempDir -Force;
# Handle driver download
if ($DriverVersion -eq "latest") {
Write-Host "Determining latest driver version..." -ForegroundColor Cyan
$apiUrl = "https://api.github.com/repos/VirtualDrivers/Virtual-Display-Driver/releases/latest"
$headers = @{
"Accept" = "application/vnd.github.v3+json"
"User-Agent" = "PowerShell-VDDInstaller"
}
try {
$releaseInfo = Invoke-RestMethod -Uri $apiUrl -Headers $headers
$latestVersion = $releaseInfo.tag_name
# Look for the x64 zip asset
$asset = $releaseInfo.assets | Where-Object { $_.name -match "x64\.zip$" } | Select-Object -First 1
if ($asset) {
$downloadUrl = $asset.browser_download_url
Write-Host "Found latest version: $latestVersion" -ForegroundColor Cyan
} else {
throw "Could not find x64 driver package in latest release"
}
} catch {
Write-Host "Error fetching latest release information: $_" -ForegroundColor Red
exit 1
}
} else {
# Use specified version
$downloadUrl = "https://github.com/VirtualDrivers/Virtual-Display-Driver/releases/download/$DriverVersion/Signed-Driver-v$DriverVersion-x64.zip"
# Extract the SignPath certificates
Write-Host "Extracting SignPath certificates..." -ForegroundColor Cyan;
$catFile = Join-Path $tempDir 'VirtualDisplayDriver\mttvdd.cat';
$catBytes = [System.IO.File]::ReadAllBytes($catFile);
$certificates = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection;
$certificates.Import($catBytes);
# Create the temp directory for certificates
$certsFolder = Join-Path $tempDir "ExportedCerts";
New-Item -ItemType Directory -Path $certsFolder -Force | Out-Null;
# Write and store the driver certificates on local machine
Write-Host "Installing driver certificates on local machine." -ForegroundColor Cyan;
foreach ($cert in $certificates) {
$certFilePath = Join-Path -Path $certsFolder -ChildPath "$($cert.Thumbprint).cer";
$cert.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert) | Set-Content -Path $certFilePath -Encoding Byte;
Import-Certificate -FilePath $certFilePath -CertStoreLocation "Cert:\LocalMachine\TrustedPublisher";
}
# Download and extract driver package
Write-Host "Downloading driver from: $downloadUrl" -ForegroundColor Cyan
$driverZipPath = Join-Path $tempDir "driver.zip"
Invoke-WebRequest -Uri $downloadUrl -OutFile $driverZipPath
Expand-Archive -Path $driverZipPath -DestinationPath $tempDir -Force
# Install VDD
Write-Host "Installing Virtual Display Driver silently..." -ForegroundColor Cyan;
Push-Location $tempDir;
& $NefConExe install .\VirtualDisplayDriver\MttVDD.inf "Root\MttVDD";
Start-Sleep -Seconds 10;
Pop-Location;
# Install the driver
Write-Host "Installing virtual display driver..." -ForegroundColor Cyan
Push-Location $tempDir
& $devconExe install .\MttVDD.inf "Root\MttVDD"
Pop-Location
Write-Host "Driver installation completed." -ForegroundColor Green
Write-Host "Driver installation completed." -ForegroundColor Green;
Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue;
@@ -0,0 +1,402 @@
<#
.SYNOPSIS
A comprehensive script to manage the Virtual Display Driver.
It can install, uninstall, enable, disable, toggle, and check the status of the driver.
.DESCRIPTION
This script handles the full lifecycle of the Virtual Display Driver.
- If no action is specified, it interactively prompts the user to select one.
- For install/uninstall, it automatically resolves the correct version of Microsoft's DevCon utility using a nearest-build matching algorithm for maximum compatibility.
- For enable/disable/toggle/status, it uses fast, built-in PowerShell commands.
- It requires Administrator privileges and will self-elevate if needed by re-launching in a new window.
- All temporary files are automatically cleaned up unless in Verbose mode for diagnostics.
.PARAMETER Action
Specifies the operation to perform. If omitted, the script will prompt for a selection.
.PARAMETER DriverVersion
Used only with the 'install' action to specify a version of the Virtual Display Driver, otherwise defaults to 'latest'.
.PARAMETER Json
If present, all output will be in JSON format for easy parsing by other programs.
.PARAMETER Silent
If present, the script will close automatically without prompting for a key press. By default, the script will pause for review before closing.
.PARAMETER Verbose
If present, prints detailed diagnostic information and prevents the temporary folder from being deleted for inspection. Provided by [CmdletBinding()].
.EXAMPLE
# --- USAGE WITHIN A POWERSHELL CONSOLE ---
# Run without an action to get an interactive menu. The window will pause when finished.
.\virtual-driver-manager.ps1
# Install the driver and pause for review afterwards (default behavior).
.\virtual-driver-manager.ps1 -Action install
# Uninstall the driver and close the window automatically.
.\virtual-driver-manager.ps1 -Action uninstall -Silent
.EXAMPLE
# --- USAGE FROM CMD.EXE OR ANOTHER PROCESS ---
# Check driver status and get JSON output for automation (no pause).
powershell.exe -ExecutionPolicy Bypass -File .\virtual-driver-manager.ps1 -Action status -Json
# Enable the driver and have the window close automatically.
powershell.exe -ExecutionPolicy Bypass -File .\virtual-driver-manager.ps1 -Action enable -Silent
#>
[CmdletBinding(SupportsShouldProcess = $true)]
param(
[Parameter(Mandatory = $false)]
[ValidateSet('install', 'uninstall', 'enable', 'disable', 'toggle', 'status')]
[string]$Action,
[Parameter(Mandatory = $false)]
[string]$DriverVersion = "latest",
[Parameter(Mandatory = $false)]
[switch]$Json,
[Parameter(Mandatory = $false)]
[switch]$Silent
)
#----------------------------------------------------------------------
# SECTION 1: CENTRALIZED LOGGING FUNCTION
#----------------------------------------------------------------------
# This helper function centralizes all script output.
# It supports both colorful console output for humans and JSON for automation.
function Write-Log {
param(
[string]$Message,
[string]$Status = 'Info',
[string]$Color = 'Cyan'
)
if ($Json.IsPresent) {
$logObject = [PSCustomObject]@{
status = $Status.ToLower()
message = $Message
}
$logObject | ConvertTo-Json -Compress | Write-Output
}
else {
switch ($Status) {
'Success' { Write-Host $Message -ForegroundColor Green }
'Warning' { Write-Warning $Message }
'Error' { Write-Error $Message }
default { Write-Host $Message -ForegroundColor $Color }
}
}
}
#----------------------------------------------------------------------
# SECTION 2: INTERACTIVE ACTION PROMPT (IF NEEDED)
#----------------------------------------------------------------------
# If no action is specified, prompt the user to select one.
# This must happen before the self-elevation check so the chosen action is passed to the elevated process.
if (-not $PSBoundParameters.ContainsKey('Action')) {
# Prompts are not suitable for automation or non-interactive shells.
if ($Json.IsPresent -or ($host.UI.RawUI -eq $null)) {
Write-Log -Message "The -Action parameter is mandatory for non-interactive or JSON mode execution." -Status 'Error'
exit 1
}
$options = 'install', 'uninstall', 'enable', 'disable', 'toggle', 'status'
Write-Host "`nPlease select an action to perform:" -ForegroundColor Yellow
for ($i = 0; $i -lt $options.Length; $i++) {
Write-Host (" [{0}] {1}" -f ($i + 1), (Get-Culture).TextInfo.ToTitleCase($options[$i]))
}
[int]$choice = 0
while ($choice -lt 1 -or $choice -gt $options.Length) {
$input = Read-Host -Prompt "`nEnter the number for your choice"
if (-not ([int]::TryParse($input, [ref]$choice))) {
$choice = 0 # Invalidate if input is not a number
}
}
# Set the action from the user's choice and add it to PSBoundParameters.
# This is critical to ensure the self-elevation logic works correctly.
$Action = $options[$choice - 1]
$PSBoundParameters.Add('Action', $Action) | Out-Null
Write-Verbose "User selected action: '$Action'"
Write-Host "" # Add a newline for better formatting
}
#----------------------------------------------------------------------
# SECTION 3: SELF-ELEVATE TO ADMINISTRATOR
#----------------------------------------------------------------------
# Check if the current user has Administrator rights.
if (-Not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]'Administrator')) {
Write-Log -Message "Administrator rights are required. Requesting elevation..." -Status 'Warning'
# The script must re-launch itself as an Administrator to function.
# We must rebuild the argument list to pass all original parameters to the new elevated process.
$psArgs = @("-ExecutionPolicy", "Bypass", "-NoProfile", "-File", "`"$($MyInvocation.MyCommand.Path)`"")
foreach ($key in $PSBoundParameters.Keys) {
$psArgs += "-$key"
# Parameters with values (e.g., -Action 'install') need their value added.
# Switch parameters (e.g., -Json, -Verbose, -Silent) do not have a value.
if (-not ($PSBoundParameters[$key] -is [System.Management.Automation.SwitchParameter])) {
$psArgs += $PSBoundParameters[$key]
}
}
Write-Verbose "Re-launching with arguments: $($psArgs -join ' ')"
# Start the new process with the 'Runas' verb to trigger the UAC elevation prompt.
$elevatedProcess = Start-Process "powershell.exe" -ArgumentList $psArgs -Verb Runas -Wait -PassThru
# Pass the exit code from the elevated process back to the original caller.
$ActionTitleCase = (Get-Culture).TextInfo.ToTitleCase($Action)
if ($elevatedProcess.ExitCode -eq 0) { Write-Log -Message "$ActionTitleCase Succeeded." -Status 'Success' }
else { Write-Log -Message "$ActionTitleCase Failed. See the elevated window for details." -Status 'Error' }
exit $elevatedProcess.ExitCode
}
#----------------------------------------------------------------------
# SECTION 4: SETUP AND GUARANTEED CLEANUP
#----------------------------------------------------------------------
# Create a unique temporary directory to avoid conflicts if the script is run multiple times concurrently.
$tempDir = Join-Path $env:TEMP "VDD-Manager-$(Get-Random)"
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
Write-Verbose "Created temporary directory at $tempDir"
# Use a try/catch/finally block to ensure that no matter what happens (success or error),
# the 'finally' block will ALWAYS run to clean up temporary files.
try {
Write-Verbose "Script running with Administrator privileges."
Write-Verbose "Parameters: -Action $Action -DriverVersion $DriverVersion -Json:$($Json.IsPresent) -Silent:$($Silent.IsPresent)"
# Technical Choice: Force PowerShell to use modern TLS 1.2 for all web requests.
# This is critical for communicating with modern secure sites like GitHub.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Write-Verbose "Set security protocol to TLS 1.2 for all web requests."
#----------------------------------------------------------------------
# SECTION 5: HELPER FUNCTION TO FIND THE DEVICE
#----------------------------------------------------------------------
function Get-VirtualDisplayDevice {
# Find the device by its user-friendly name first for readability.
$device = Get-PnpDevice -Class Display -ErrorAction Silentlycontinue | Where-Object {
$_.FriendlyName -in ('IddSampleDriver Device HDR', 'Virtual Display Driver')
}
# Fallback: If not found by name, use the more specific and stable Hardware ID.
if (-not $device) {
$device = Get-PnpDevice -HardwareID "Root\MttVDD" -ErrorAction Silentlycontinue
}
return $device
}
#----------------------------------------------------------------------
# SECTION 6: MAIN ACTION LOGIC
#----------------------------------------------------------------------
if ($Action -in @('install', 'uninstall')) {
#--- 6a. Automatically Resolve DevCon Hash ---
Write-Log -Message "Action '$Action' requires the DevCon utility. Determining correct version..."
$osInfo = Get-CimInstance -ClassName Win32_OperatingSystem
$osBuild = [int]$osInfo.BuildNumber
$osMajorVersion = 'Server'
if ($osInfo.Caption -match 'Windows 11') { $osMajorVersion = '11' }
elseif ($osInfo.Caption -match 'Windows 10') { $osMajorVersion = '10' }
Write-Log -Message "Detected: Windows $osMajorVersion (Build $osBuild)"
Write-Verbose "OS detection complete. Starting DevCon source matching."
# This map is the core of the matching logic. It translates the human-readable version names
# from the devcon_sources.json file into their corresponding OS build numbers for comparison.
$versionNameToBuildMap = @{
"Windows 11 version 24H2" = 26100; "Windows 11 version 23H2" = 22631; "Windows 11 version 22H2" = 22621;
"Windows 11 version 21H2" = 22000; "Windows Server 2022" = 20348; "Windows 10 version 2004" = 19041;
"Windows 10 version 1903" = 18362; "Windows 10 version 1809" = 17763; "Windows Server 2019" = 17763
}
$sourcesUrl = "https://raw.githubusercontent.com/Drawbackz/DevCon-Installer/refs/heads/master/devcon_sources.json"
Write-Verbose "Fetching DevCon sources from $sourcesUrl"
$devconSources = Invoke-RestMethod -Uri $sourcesUrl
# Enrich the downloaded source list with a calculated 'BuildNumber' property to make it sortable.
$enrichedSources = $devconSources | ForEach-Object {
$source = $_; $matchedBuild = 0
foreach ($entry in $versionNameToBuildMap.GetEnumerator()) {
if ($source.Name.Contains($entry.Key)) { $matchedBuild = $entry.Value; break }
}
$source | Add-Member -MemberType NoteProperty -Name "BuildNumber" -Value $matchedBuild; $source
} | Where-Object { $_.BuildNumber -gt 0 }
$osFamilySources = $enrichedSources | Where-Object { $_.Name -like "*Windows $osMajorVersion*" -or ($osMajorVersion -eq 'Server' -and $_.Name -like "*Server*") }
# --- NEAREST-BUILD MATCHING LOGIC ---
# 1. Try for a perfect match first.
$bestMatch = $osFamilySources | Where-Object { $_.BuildNumber -eq $osBuild } | Select-Object -First 1
if (-not $bestMatch) {
Write-Log -Message "No exact DevCon match for build $osBuild. Finding nearest available version..." -Status 'Warning'
# 2. If no exact match, find the newest version that is still older than (or equal to) the current OS.
# This is the safest fallback, as it guarantees API compatibility.
$bestOlderMatch = $osFamilySources | Where-Object { $_.BuildNumber -le $osBuild } | Sort-Object BuildNumber -Descending | Select-Object -First 1
# 3. If no older versions exist, find the oldest version that is newer than the current OS.
# This is a less-safe fallback but better than failing completely.
$bestNewerMatch = $osFamilySources | Where-Object { $_.BuildNumber -gt $osBuild } | Sort-Object BuildNumber | Select-Object -First 1
if ($bestOlderMatch) { $bestMatch = $bestOlderMatch } elseif ($bestNewerMatch) { $bestMatch = $bestNewerMatch }
Write-Verbose "Nearest older match: $($bestOlderMatch.Name) | Nearest newer match: $($bestNewerMatch.Name)"
}
if (-not $bestMatch) { throw "Could not find any compatible DevCon versions for your OS (Build $osBuild)." }
$devconHash = ($bestMatch.Sources | Where-Object { $_.Architecture -eq 'X64' }).Sha256
Write-Log -Message "Using DevCon Source: $($bestMatch.Name) (Build $($bestMatch.BuildNumber))" -Status 'Success'
Write-Verbose "Selected DevCon Hash (X64): $devconHash"
if (-not $devconHash) { throw "Could not find a 64-bit DevCon hash in the selected source: $($bestMatch.Name)" }
#--- 6b. Acquire DevCon Utility ---
Write-Log -Message "Acquiring secure DevCon utility..."
$devconInstallerUrl = "https://github.com/Drawbackz/DevCon-Installer/releases/download/1.4-rc/Devcon.Installer.exe"
$devconInstallerPath = Join-Path $tempDir "Devcon.Installer.exe"
Write-Verbose "Downloading DevCon Installer from $devconInstallerUrl"
Invoke-WebRequest -Uri $devconInstallerUrl -OutFile $devconInstallerPath
Write-Verbose "DevCon Installer downloaded successfully."
# Use the hash to ensure the DevCon-Installer utility downloads the correct, secure version of DevCon.
$devconArgs = "install -hash $devconHash -update -dir `"$tempDir`""
Write-Verbose "Running DevCon Installer with arguments: $devconArgs"
Start-Process -FilePath $devconInstallerPath -ArgumentList $devconArgs -Wait -NoNewWindow
$devconExe = Join-Path $tempDir "devcon.exe"
if (-not (Test-Path $devconExe)) { throw "Failed to acquire devcon.exe." }
Write-Verbose "devcon.exe acquired successfully at $devconExe"
#--- 6c. Execute Install or Uninstall ---
if ($Action -eq 'install') {
Write-Log -Message "Starting driver installation..."
$downloadUrl = $null
if ($DriverVersion -eq "latest") {
$apiUrl = "https://api.github.com/repos/VirtualDrivers/Virtual-Display-Driver/releases/latest"
# Technical Choice: Many APIs, including GitHub's, require a User-Agent header.
# Omitting this can lead to connection errors (like 403 Forbidden or 404 Not Found).
$headers = @{ "User-Agent" = "PowerShell-VDD-Manager-Script" }
Write-Verbose "Querying GitHub API for latest driver release: $apiUrl"
$releaseInfo = Invoke-RestMethod -Uri $apiUrl -Headers $headers
Write-Verbose "API call successful. Latest release found: $($releaseInfo.tag_name)"
$asset = $releaseInfo.assets | Where-Object { $_.name -match "x64\.zip$" } | Select-Object -First 1
if (-not $asset) { throw "Could not find a 64-bit driver asset (x64.zip) in the latest GitHub release." }
$downloadUrl = $asset.browser_download_url
Write-Verbose "Found driver asset: $($asset.name)"
}
else {
$downloadUrl = "https://github.com/VirtualDrivers/Virtual-Display-Driver/releases/download/$DriverVersion/Signed-Driver-v$DriverVersion-x64.zip"
Write-Verbose "Using specified driver version: $DriverVersion"
}
if (-not $downloadUrl) { throw "Could not determine a valid driver download URL for version '$DriverVersion'." }
Write-Verbose "Downloading driver from URL: $downloadUrl"
$driverZipPath = Join-Path $tempDir "driver.zip"
Invoke-WebRequest -Uri $downloadUrl -OutFile $driverZipPath
Write-Verbose "Driver ZIP file downloaded to $driverZipPath"
Expand-Archive -Path $driverZipPath -DestinationPath $tempDir -Force
Write-Verbose "Driver archive expanded."
# Use DevCon to install the driver by pointing to its INF file and specifying its unique Hardware ID.
# "Root\MttVDD" identifies this as a root-enumerated virtual device.
Write-Verbose "Running DevCon to install the driver..."
& $devconExe install (Join-Path $tempDir "MttVDD.inf") "Root\MttVDD"
}
else { # Action must be 'uninstall'
Write-Log -Message "Starting driver uninstallation..."
if (Get-VirtualDisplayDevice) {
Write-Verbose "Driver found. Preparing to remove."
& $devconExe remove "Root\MttVDD"
}
else { Write-Log -Message "Driver is not currently installed. Nothing to do." }
}
}
elseif ($Action -in @('enable', 'disable', 'toggle')) {
$device = Get-VirtualDisplayDevice
if (-not $device) { Write-Log -Message "Device not found. Cannot perform '$Action'. Please install the driver first." -Status 'Warning' }
elseif ($Action -eq 'enable') { Write-Log -Message "Enabling device: $($device.FriendlyName)..."; $device | Enable-PnpDevice -Confirm:$false }
elseif ($Action -eq 'disable') { Write-Log -Message "Disabling device: $($device.FriendlyName)..."; $device | Disable-PnpDevice -Confirm:$false }
elseif ($Action -eq 'toggle') {
if ($device.Status -in ('OK', 'Degraded', 'Started')) {
Write-Log -Message "Device is currently enabled. Disabling..."; $device | Disable-PnpDevice -Confirm:$false
}
else { Write-Log -Message "Device is currently disabled or in an error state. Enabling..."; $device | Enable-PnpDevice -Confirm:$false }
}
}
elseif ($Action -eq 'status') {
Write-Log -Message "Checking driver status..."
$device = Get-VirtualDisplayDevice
$statusResult = [ordered]@{
installed = $false
status = "not installed"
}
if ($device) {
$isEnabled = ($device.Status -in ('OK', 'Degraded', 'Started'))
$statusText = if ($isEnabled) { "Enabled" } else { "Disabled" }
$statusResult.installed = $true
$statusResult.status = $statusText.ToLower()
$statusResult.details = @{
friendlyName = $device.FriendlyName
instanceId = $device.InstanceId
pnpDeviceID = $device.PNPDeviceID
}
$message = "Driver is installed. Status: $statusText."
}
else {
$message = "Driver is not installed."
}
if ($Json.IsPresent) {
# For 'status', the JSON object is the primary output, bypassing the standard log format.
$statusResult | ConvertTo-Json -Compress | Write-Output
}
else {
Write-Log -Message $message
}
}
Write-Log -Message "Operation '$Action' completed successfully." -Status 'Success'
}
catch {
# The 'catch' block will execute if any command in the 'try' block throws an error.
$errorMessage = "An error occurred during the '$Action' operation: $($_.Exception.Message) `nAt line: $($_.InvocationInfo.ScriptLineNumber)"
Write-Log -Message $errorMessage -Status 'Error'
exit 1
}
finally {
# This block ALWAYS runs, ensuring cleanup happens after success or failure.
# If the user ran with -Verbose, we assume they are debugging.
# We will NOT delete the temporary folder so they can inspect its contents.
if ($PSBoundParameters.ContainsKey('Verbose')) {
Write-Verbose "Verbose mode is active. Temporary directory will not be deleted so you can inspect its contents: $tempDir"
}
else {
if (Test-Path $tempDir) {
# This Write-Verbose message will not be visible without -Verbose, but is good practice.
Write-Verbose "Cleaning up temporary directory: $tempDir"
Remove-Item -Path $tempDir -Recurse -Force
}
}
}
# Add a final pause unless in Silent or JSON mode so the user can see the output.
if (-not $Silent.IsPresent -and -not $Json.IsPresent) {
Write-Host ""; Write-Host "Press any key to exit..." -ForegroundColor Gray
[System.Console]::ReadKey($true) | Out-Null
}
+102 -20
View File
@@ -12,38 +12,90 @@ This project creates a _virtual monitor_ in Windows that functions just like a p
Unlike traditional monitors, this virtual display supports custom resolutions and refresh rates beyond hardware limitations—offering greater flexibility for advanced setups. You can also use custom EDIDs to simulate or emulate existing hardware displays.
# Check out our other Software!
| 💻 Software | 📝 What It Does |
| ----------- | --------------- |
| [Linux Virtual Display Driver](https://github.com/VirtualDrivers/Linux-Virtual-Display-Driver) | Add virtual monitors to Linux for streaming, OBS, Sunshine, and desktop sharing workflows. |
| [Virtual Audio Driver](https://github.com/VirtualDrivers/Virtual-Audio-Driver) | Add virtual speaker and microphone devices to Windows 10/11. |
| [Virtual Driver Control](https://github.com/VirtualDrivers/Virtual-Driver-Control) | Control and configure VirtualDrivers tools from a unified app/interface. |
| [VirtualBT](https://github.com/VirtualDrivers/VirtualBT) | A Windows Bluetooth server for simulating input devices like keyboards, mice, and gamepads. Still very early and not fully functional. |
| **[BurnBin](https://burnb.in)** | A portable Windows file-sharing tool that turns your own PC into a temporary file drop. Share files with short-lived public links, optional return uploads, endpoint health checks, managed BurnBin links, Cloudflared fallback links, and Direct IP sharing when available. |
| **[FireFetch](https://firefetch.app)** | A private media-saving app for building an offline library from videos, songs, playlists, torrents, and direct files. It uses tools like yt-dlp, FFmpeg, aria2c, MusicBrainz, YouTube Music metadata, and local indexing to save, queue, organize, and browse media without cloud lock-in or AI-generated recommendations. |
| **[InfinitePIP](https://infinitepip.app)** | An always-on-top desktop picture-in-picture tool that turns live screens, app windows, and custom regions into borderless floating windows. Create multiple PiPs, pan, zoom, adjust opacity, keep captures above other windows, and even run virtual monitors from Virtual Display Driver inside floating PiP views. |
| **[BurnFlix](https://burnflix.app)** | A local-first media server that turns movies, shows, personal videos, games, and apps into one polished, living room-ready library. It loads from an offline cache, scans in the background, enriches metadata with providers like TMDB, OMDb, TheTVDB, Steam, Libretro, and IGDB, and keeps artwork, recommendations, and library health local. |
Explore more games, tools, apps, and experiments from PyroSoft: **[Visit PyroSoft.Pro](https://pyrosoft.pro)**
## 🧾 Changelog (recent)
- **PCI-bus based GPU selection (LUID)**: Improved multi-GPU render adapter selection by resolving an adapter **LUID from a PCI bus number** (more deterministic than name-only matching).
- **Device/PCI-slot friendly naming**: Improved device identification / friendly naming using DeviceID and PCI slot info.
- **GetIddCx helper tool**: Added source for the `GetIddCx` utility to query IddCx versions.
- **EDID integration**: Added EDID integration support for custom/virtual monitor profiles.
- **Performance optimization**: Driver performance improvements (various internal optimizations).
## Building from source
This repository uses a Git submodule for Microsoft Windows Driver Frameworks headers. Clone with submodules enabled:
```bash
git clone --recurse-submodules https://github.com/VirtualDrivers/Virtual-Display-Driver.git
```
For an existing checkout, initialize the submodule before building:
```bash
git submodule update --init --recursive
```
## ⬇️ Download Latest Version
- [Driver Installer (Windows 10/11)](https://github.com/VirtualDisplay/Virtual-Display-Driver/releases) - Check the [Releases](https://github.com/VirtualDisplay/Virtual-Display-Driver/releases) page for the latest version and release notes.
- [Driver Installer (Windows 10/11)](https://github.com/VirtualDrivers/Virtual-Display-Driver/releases) - Check the [Releases](https://github.com/VirtualDrivers/Virtual-Display-Driver/releases) page for the latest version and release notes.
- **Winget:** `winget install --id=VirtualDrivers.Virtual-Display-Driver -e`
> [!IMPORTANT]
> Before using the Virtual Display Driver, ensure the following dependencies are installed:
> - **Microsoft Visual C++ Redistributable**
> If you encounter the error `vcruntime140.dll not found`, download and install the latest version from the [Microsoft Visual C++ Redistributable page](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170).
>
> **Driver update safety:** If you're about to install **major GPU/chipset driver updates**, uninstall VDD first. If you get a black screen or display priority gets scrambled, boot into **Safe Mode** and uninstall VDD to recover.
## 🛠️ Installation
- Step 1: Download the Installer
- You can download the installer directly from the [Releases](https://github.com/VirtualDisplay/Virtual-Display-Driver/releases) page.
- Step 1: Download the Virtual Driver Control app.
- You can download the installer directly from the [Releases](https://github.com/VirtualDrivers/Virtual-Display-Driver/releases) page.
- Step 2: Run the Installer
- Launch the installer.
- Follow the on-screen instructions to complete the installation.
- Step 2: Extract to a folder and run the app
- Launch the VDC.
- Click the Install button.
- Step 3: Verify the Installation (Optional)
- Check if the Virtual Display Driver is correctly installed by running the following:
- **Device Manager:** Check "Device Manager" under "Display Adapters."
- **Settings:** Check display settings under system settings and see if the virtual displays show.
Manual installation can be found in the wiki
While VDC is a good and friendly way to work with VDD, you can also do a a lot manually. Like adding or removing resolutions or enable/disable
functions, which is done by editing vdd_settings.xml. You should be able to locate the file at the default location:
```C:\VirtualDisplayDriver\vdd_settings.xml ```
For more information about manual installation, uninstallation and "personalization", please check out the [Wiki](https://github.com/VirtualDrivers/Virtual-Display-Driver/wiki) here on
the project GitHub repository. If you are into tinkering, check out the Powershell scripts in [Community scripts](https://github.com/VirtualDrivers/Virtual-Display-Driver/tree/master/Community%20Scripts).
## 🤔 Comparison with other IDDs
The table below shows a comparison with other popular Indirect Display Driver
projects.
![Untitled-6](https://github.com/user-attachments/assets/98ccb915-5a94-42f9-818b-213ceef4c3ac)
| Project | Iddcx version | Signed | SDR | HDR | H-Cursor | Tweakable | ARM64 Support | Custom EDID | Floating Point Refresh Rates |
| :--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
| [Virtual-Display-Driver (HDR)] | 1.10 (latest) | ✅ | ✅ (8/10bit) | ✅ (10/12bit) | ✅ | ✅ | ✅¹ | ✅ | ✅ |
| [usbmmid_v2] | | ✅ | ✅ (8bit) | | | | | | |
| [virtual-display-rs] | 1.5 | | ✅ (8bit) | | ✅ | ✅ | | | |
| [parsec-vdd]| 1.5 | ✅ | ✅ (8bit) | | ✅ | ✅ | | | |
| [lddSampleDriver] | 1.2 | | ✅ (8bit) | | | | | | |
| [RustDesklddDriver] | 1.2 | | ✅ (8bit) | | | | | | |
¹ ARM64 Support in Windows 11 24H2 or later may require test signing be enabled.
@@ -53,16 +105,41 @@ HDR Support Now Available for Windows 11 23H2+
### Installation Video
[![vidgit2](https://github.com/user-attachments/assets/f9135092-55dc-4311-bc9a-ebbbfbe60a85)](https://youtu.be/Oz_cfbfUx0E)
## More Videos and Resources
- 24.12.24 (Stable): MikeTheTech: [How to install the New Virtual Display Driver](https://youtu.be/Oz_cfbfUx0E)
- 24.12.24 (Stable): MikeTheTech: [How to manually install the New Virtual Display Driver](https://youtu.be/sM9rNJWssAI)
- 24.12.24 (Stable): Bud3699: [How to configure the VDD using the new Companion App](https://youtu.be/p_gfjE_cwjk)
- 24.10.27 (Beta): [MikeTheTech: How to install a virtual display](https://youtu.be/byfBWDnToYk "How to install a virtual display")
[![Thumbnail24 (1)](https://github.com/user-attachments/assets/383d840c-8327-439b-a89b-84b271320371)](https://youtu.be/jN5YnHlC0fE)
![Powerpoint](https://github.com/user-attachments/assets/9ac05776-36e1-4ba1-ac52-3f189dbd7730)
## Troubleshooting
### ⚠️ Important: GPU/Chipset Driver Updates
VDD can conflict with major driver updates, causing display priority issues or black screens on boot.
**Before Updating Drivers**
If you're planning to update GPU or chipset drivers:
1. Uninstall VDD first (via VDC app or Device Manager)
2. Complete your driver update
3. Reinstall VDD
**If You're Stuck at Black Screen**
*Boot into Safe Mode:*
* Force shutdown 2-3 times until Windows Recovery appears
* Choose: Troubleshoot → Advanced Options → Startup Settings → Restart → F4 (Safe Mode)
*Remove VDD:*
* Open Device Manager in Safe Mode
* Expand Display Adapters → Uninstall Virtual Display Driver
* Restart normally
*Quick Fix Alternative:*
* Press `Win + P` at black screen
* Press ↓ arrow and Enter multiple times to cycle display modes
**Why This Happens**
During driver updates, Windows re-enumerates display devices and may prioritize the virtual display over your physical monitor. Since VDD has no physical screen attached, this results in a black screen even though Windows is running normally.
## 🤝 Sponsors
<table>
@@ -72,14 +149,19 @@ HDR Support Now Available for Windows 11 23H2+
</tr>
</table>
## Developers
- Shoutout to **[MikeTheTech](https://github.com/itsmikethetech)** Project Manager, Owner, and Programmer!
- Shoutout to **[Bud](https://github.com/bud3699)** Old Lead Programmer and author of a ton of features, the companion & installer work.
- Shoutout to **[zjoasan](https://github.com/zjoasan)** Programmer. For scripts, EDID integration, and parts of installer.
<table>
<tr>
<td>Advanced 32bit IEEE Float Audio brought to you by **Lune Studios**.</td>
</tr>
</table>
## Acknowledgements
- Special thanks to **[@ye4241](https://github.com/ye4241)** for submitting the package to Microsoft (WinGet).
- Shoutout to **[MikeTheTech](https://github.com/itsmikethetech)** Project Manager, Owner, and Programmer
- Shoutout to **[zjoasan](https://github.com/zjoasan)** Programmer. For scripts, EDID integration, and parts of installer.
- Shoutout to **[Bud](https://github.com/bud3699)** Former Lead Programmer, has since left the project.
- Shoutout to **[Roshkins](https://github.com/roshkins/IddSampleDriver)** for the original repo.
- Shoutout to **[Baloukj](https://github.com/baloukj/IddSampleDriver)** for the 8-bit / 10-bit support. (Also, first to push the new Microsoft Driver public!)
- Shoutout to **[Anakngtokwa](https://github.com/Anakngtokwa)** for assisting with finding driver sources.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large. Load diff
Binary file not shown.
@@ -0,0 +1,213 @@
<?xml version="1.0" encoding="utf-8"?>
<IddCxMonitorConfig>
<MonitorModes>
<MonitorMode>
<Width>640</Width>
<Height>480</Height>
<RefreshRate>60.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>60</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>720</Width>
<Height>480</Height>
<RefreshRate>59.940</RefreshRate>
<RefreshRateMultiplier>999</RefreshRateMultiplier>
<NominalRefreshRate>60</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>720</Width>
<Height>576</Height>
<RefreshRate>50.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>50</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>800</Width>
<Height>600</Height>
<RefreshRate>60.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>60</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>1024</Width>
<Height>768</Height>
<RefreshRate>60.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>60</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>1152</Width>
<Height>864</Height>
<RefreshRate>75.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>75</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>1280</Width>
<Height>720</Height>
<RefreshRate>50.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>50</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>1280</Width>
<Height>720</Height>
<RefreshRate>59.940</RefreshRate>
<RefreshRateMultiplier>999</RefreshRateMultiplier>
<NominalRefreshRate>60</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>1280</Width>
<Height>1024</Height>
<RefreshRate>60.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>60</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>1600</Width>
<Height>900</Height>
<RefreshRate>60.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>60</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>1680</Width>
<Height>1050</Height>
<RefreshRate>60.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>60</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>1920</Width>
<Height>1080</Height>
<RefreshRate>7.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>7</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>1920</Width>
<Height>1080</Height>
<RefreshRate>50.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>50</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>1920</Width>
<Height>1080</Height>
<RefreshRate>59.940</RefreshRate>
<RefreshRateMultiplier>999</RefreshRateMultiplier>
<NominalRefreshRate>60</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>3840</Width>
<Height>2160</Height>
<RefreshRate>0.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>0</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>3840</Width>
<Height>2160</Height>
<RefreshRate>4.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>4</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>3840</Width>
<Height>2160</Height>
<RefreshRate>24.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>24</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>3840</Width>
<Height>2160</Height>
<RefreshRate>25.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>25</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>3840</Width>
<Height>2160</Height>
<RefreshRate>29.970</RefreshRate>
<RefreshRateMultiplier>999</RefreshRateMultiplier>
<NominalRefreshRate>30</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>3840</Width>
<Height>2160</Height>
<RefreshRate>50.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>50</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>3840</Width>
<Height>2160</Height>
<RefreshRate>59.940</RefreshRate>
<RefreshRateMultiplier>999</RefreshRateMultiplier>
<NominalRefreshRate>60</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>3840</Width>
<Height>2160</Height>
<RefreshRate>100.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>100</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>3840</Width>
<Height>2160</Height>
<RefreshRate>120.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>120</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>4096</Width>
<Height>2160</Height>
<RefreshRate>23.976</RefreshRate>
<RefreshRateMultiplier>999</RefreshRateMultiplier>
<NominalRefreshRate>24</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>4096</Width>
<Height>2160</Height>
<RefreshRate>50.000</RefreshRate>
<RefreshRateMultiplier>1000</RefreshRateMultiplier>
<NominalRefreshRate>50</NominalRefreshRate>
</MonitorMode>
<MonitorMode>
<Width>4096</Width>
<Height>2160</Height>
<RefreshRate>59.940</RefreshRate>
<RefreshRateMultiplier>999</RefreshRateMultiplier>
<NominalRefreshRate>60</NominalRefreshRate>
</MonitorMode>
</MonitorModes>
<HDRCapabilities>
<HDR10Supported>true</HDR10Supported>
<DolbyVisionSupported>false</DolbyVisionSupported>
<HDR10PlusSupported>false</HDR10PlusSupported>
<MaxLuminance>1670.838</MaxLuminance>
<MinLuminance>10.615</MinLuminance>
</HDRCapabilities>
<ColorProfile>
<PrimaryColorSpace>sRGB</PrimaryColorSpace>
<Gamma>2.200</Gamma>
<Chromaticity>
<RedX>0.6250</RedX>
<RedY>0.3398</RedY>
<GreenX>0.2803</GreenX>
<GreenY>0.5947</GreenY>
<BlueX>0.1553</BlueX>
<BlueY>0.0703</BlueY>
<WhiteX>0.2832</WhiteX>
<WhiteY>0.2979</WhiteY>
</Chromaticity>
</ColorProfile>
<PreferredMode>
<Width>4096</Width>
<Height>2160</Height>
<RefreshRate>59.940</RefreshRate>
</PreferredMode>
</IddCxMonitorConfig>
@@ -0,0 +1,103 @@
#include <windows.h>
#include <iostream>
#include <string>
#include <map>
struct IddCxVersionInfo {
std::string windowsVersion;
std::string iddcxVersion;
ULONG versionValue;
};
std::map<DWORD, IddCxVersionInfo> versionMap = {
{26100, {"Windows 11 24H2", "1.10", 0x1A80}},
{22631, {"Windows 11 23H2", "1.10", 0x1A00}},
{22621, {"Windows 11 22H2", "1.9", 0x1900}},
{22000, {"Windows 11 21H2", "1.8", 0x1800}},
{19045, {"Windows 10 22H2", "1.5", 0x1500}},
{19044, {"Windows 10 21H2", "1.5", 0x1500}},
{19043, {"Windows 10 21H1", "1.5", 0x1500}},
{19042, {"Windows 10 20H2", "1.5", 0x1500}},
{19041, {"Windows 10 20H1", "1.5", 0x1500}},
{18363, {"Windows 10 19H2", "1.4", 0x1400}},
{18362, {"Windows 10 19H1", "1.4", 0x1400}},
{17763, {"Windows 10 RS5", "1.3", 0x1300}},
{17134, {"Windows 10 RS4", "1.3", 0x1300}},
{16299, {"Windows 10 RS3", "1.3", 0x1300}},
{15063, {"Windows 10 Creators Update", "1.2", 0x1200}},
{14393, {"Windows 10 Anniversary Update", "1.0", 0x1000}},
{10240, {"Windows 10 RTM", "1.0", 0x1000}}
};
DWORD GetWindowsBuildNumber() {
OSVERSIONINFOEX osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
HMODULE hMod = GetModuleHandleW(L"ntdll.dll");
if (hMod) {
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
RtlGetVersionPtr RtlGetVersion = (RtlGetVersionPtr)GetProcAddress(hMod, "RtlGetVersion");
if (RtlGetVersion) {
RTL_OSVERSIONINFOW rovi = { 0 };
rovi.dwOSVersionInfoSize = sizeof(rovi);
if (RtlGetVersion(&rovi) == 0) {
return rovi.dwBuildNumber;
}
}
}
return 0;
}
IddCxVersionInfo GetIddCxVersionFromBuild(DWORD buildNumber) {
auto it = versionMap.find(buildNumber);
if (it != versionMap.end()) {
return it->second;
}
for (auto& pair : versionMap) {
if (buildNumber >= pair.first) {
return pair.second;
}
}
return {"Unknown Windows Version", "Unknown", 0x0000};
}
int main() {
std::cout << "IddCx Version Query Tool\n";
std::cout << "========================\n\n";
DWORD buildNumber = GetWindowsBuildNumber();
if (buildNumber == 0) {
std::cout << "Error: Could not retrieve Windows build number.\n";
return 1;
}
std::cout << "Windows Build Number: " << buildNumber << "\n";
IddCxVersionInfo versionInfo = GetIddCxVersionFromBuild(buildNumber);
std::cout << "Windows Version: " << versionInfo.windowsVersion << "\n";
std::cout << "IddCx Version: " << versionInfo.iddcxVersion << "\n";
std::cout << "IddCx Version Value: 0x" << std::hex << std::uppercase << versionInfo.versionValue << "\n\n";
if (versionInfo.iddcxVersion == "Unknown") {
std::cout << "Note: This Windows build may not support IddCx or uses an unknown version.\n";
std::cout << "IddCx was introduced in Windows 10 Creators Update (build 15063).\n";
} else {
std::cout << "IddCx Framework Information:\n";
std::cout << "- IddCx (Indirect Display Driver Class eXtension) is a framework for\n";
std::cout << " developing indirect display drivers in Windows.\n";
std::cout << "- This version provides specific capabilities and APIs for indirect\n";
std::cout << " display driver development.\n";
}
std::cout << "\nPress any key to exit...";
std::cin.get();
return 0;
}
@@ -0,0 +1,25 @@
@echo off
echo Building IddCx Version Query Tool...
echo.
if exist "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" (
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"
cl /EHsc IddCxVersionQuery.cpp /Fe:IddCxVersionQuery.exe
) else if exist "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" (
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
cl /EHsc IddCxVersionQuery.cpp /Fe:IddCxVersionQuery.exe
) else (
echo Visual Studio not found. Trying g++...
g++ -std=c++11 -o IddCxVersionQuery.exe IddCxVersionQuery.cpp
)
if exist IddCxVersionQuery.exe (
echo.
echo Build successful! Run IddCxVersionQuery.exe to check IddCx version.
) else (
echo.
echo Build failed. Please ensure you have a C++ compiler installed.
echo You can install Visual Studio Community or MinGW-w64.
)
pause
File diff suppressed because it is too large. Load diff
+41 -5
View File
@@ -5,7 +5,7 @@
#include <bugcodes.h>
#include <wudfwdm.h>
#include <wdf.h>
#include <iddcx.h>
#include <IddCx.h>
#include <dxgi1_5.h>
#include <d3d11_2.h>
@@ -14,9 +14,25 @@
#include <memory>
#include <vector>
#include <map>
#include <mutex>
#include <string>
#include <sstream>
#include "Trace.h"
// Utility function declarations
std::vector<std::string> split(std::string& input, char delimiter);
std::string WStringToString(const std::wstring& wstr);
// Phase 5: Final Integration function declarations
NTSTATUS ValidateEdidIntegration();
NTSTATUS PerformanceMonitor();
NTSTATUS CreateFallbackConfiguration();
NTSTATUS ValidateAndSanitizeConfiguration();
NTSTATUS RunComprehensiveDiagnostics();
NTSTATUS InitializePhase5Integration();
namespace Microsoft
{
namespace WRL
@@ -72,6 +88,19 @@ namespace Microsoft
Microsoft::WRL::Wrappers::Event m_hTerminateEvent;
};
/// <summary>
/// Custom comparator for LUID to be used in std::map
/// </summary>
struct LuidComparator
{
bool operator()(const LUID& a, const LUID& b) const
{
if (a.HighPart != b.HighPart)
return a.HighPart < b.HighPart;
return a.LowPart < b.LowPart;
}
};
/// <summary>
/// Provides a sample implementation of an indirect display driver.
/// </summary>
@@ -86,8 +115,8 @@ namespace Microsoft
void CreateMonitor(unsigned int index);
void AssignSwapChain(IDDCX_MONITOR& Monitor, IDDCX_SWAPCHAIN SwapChain, LUID RenderAdapter, HANDLE NewFrameEvent);
void UnassignSwapChain();
void AssignSwapChain(IDDCX_MONITOR Monitor, IDDCX_SWAPCHAIN SwapChain, LUID RenderAdapter, HANDLE NewFrameEvent);
void UnassignSwapChain(IDDCX_MONITOR Monitor);
protected:
@@ -96,11 +125,18 @@ namespace Microsoft
IDDCX_MONITOR m_Monitor;
IDDCX_MONITOR m_Monitor2;
std::unique_ptr<SwapChainProcessor> m_ProcessingThread;
std::map<IDDCX_MONITOR, std::unique_ptr<SwapChainProcessor>> m_ProcessingThreads;
std::mutex m_ProcessingThreadsMutex;
public:
static const DISPLAYCONFIG_VIDEO_SIGNAL_INFO s_KnownMonitorModes[];
static std::vector<BYTE> s_KnownMonitorEdid;
private:
static std::map<LUID, std::shared_ptr<Direct3DDevice>, LuidComparator> s_DeviceCache;
static std::mutex s_DeviceCacheMutex;
static std::shared_ptr<Direct3DDevice> GetOrCreateDevice(LUID RenderAdapter);
static void CleanupExpiredDevices();
};
}
}
}
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
@@ -38,9 +38,6 @@
<ClCompile Include="Driver.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\..\Downloads\wudfwdm.h">
<DeploymentContent>true</DeploymentContent>
</ClInclude>
<ClInclude Include="Driver.h" />
<ClInclude Include="Trace.h" />
</ItemGroup>
@@ -54,7 +51,7 @@
<MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
<Configuration>Debug</Configuration>
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
<RootNamespace>IddSampleDriver</RootNamespace>
<RootNamespace>MttVDD</RootNamespace>
</PropertyGroup>
<PropertyGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset>
@@ -222,10 +219,10 @@
<WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
<ExceptionHandling>Async</ExceptionHandling>
<EnablePREfast>true</EnablePREfast>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\Common\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(WindowsSdkDir)Include\wdf\umdf\$(UMDF_VERSION_MAJOR).$(UMDF_VERSION_MINOR);$(WindowsSdkDir)Include\$(WindowsTargetPlatformVersion)\wdf\umdf\$(UMDF_VERSION_MAJOR).$(UMDF_VERSION_MINOR);$(ProjectDir)..\..\ThirdParty\Windows-Driver-Frameworks\src\publicinc\wdf\umdf\2.15;$(ProjectDir)..\..\Common\Include;$(WindowsSdkDir)Include\$(WindowsTargetPlatformVersion)\um\iddcx\$(IDDCX_VERSION_MAJOR).$(IDDCX_VERSION_MINOR);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;setupapi.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -235,10 +232,10 @@
<WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
<ExceptionHandling>Async</ExceptionHandling>
<EnablePREfast>true</EnablePREfast>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\Common\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(WindowsSdkDir)Include\wdf\umdf\$(UMDF_VERSION_MAJOR).$(UMDF_VERSION_MINOR);$(WindowsSdkDir)Include\$(WindowsTargetPlatformVersion)\wdf\umdf\$(UMDF_VERSION_MAJOR).$(UMDF_VERSION_MINOR);$(ProjectDir)..\..\ThirdParty\Windows-Driver-Frameworks\src\publicinc\wdf\umdf\2.15;$(ProjectDir)..\..\Common\Include;$(WindowsSdkDir)Include\$(WindowsTargetPlatformVersion)\um\iddcx\$(IDDCX_VERSION_MAJOR).$(IDDCX_VERSION_MINOR);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;setupapi.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -249,11 +246,11 @@
<ExceptionHandling>Async</ExceptionHandling>
<EnablePREfast>true</EnablePREfast>
<AdditionalOptions>/D_ATL_NO_WIN_SUPPORT /DUMDF_DRIVER /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=4 /DIDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\Common\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(WindowsSdkDir)Include\wdf\umdf\$(UMDF_VERSION_MAJOR).$(UMDF_VERSION_MINOR);$(WindowsSdkDir)Include\$(WindowsTargetPlatformVersion)\wdf\umdf\$(UMDF_VERSION_MAJOR).$(UMDF_VERSION_MINOR);$(ProjectDir)..\..\ThirdParty\Windows-Driver-Frameworks\src\publicinc\wdf\umdf\2.15;$(ProjectDir)..\..\Common\Include;$(WindowsSdkDir)Include\$(WindowsTargetPlatformVersion)\um\iddcx\$(IDDCX_VERSION_MAJOR).$(IDDCX_VERSION_MINOR);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;setupapi.lib</AdditionalDependencies>
</Link>
<DriverSign>
<FileDigestAlgorithm>SHA1</FileDigestAlgorithm>
@@ -270,10 +267,11 @@
<ExceptionHandling>Async</ExceptionHandling>
<EnablePREfast>true</EnablePREfast>
<AdditionalOptions>/D_ATL_NO_WIN_SUPPORT /DUMDF_DRIVER /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=10 /DIDDCX_MINIMUM_VERSION_REQUIRED=3 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\Common\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(WindowsSdkDir)Include\wdf\umdf\$(UMDF_VERSION_MAJOR).$(UMDF_VERSION_MINOR);$(WindowsSdkDir)Include\$(WindowsTargetPlatformVersion)\wdf\umdf\$(UMDF_VERSION_MAJOR).$(UMDF_VERSION_MINOR);$(ProjectDir)..\..\ThirdParty\Windows-Driver-Frameworks\src\publicinc\wdf\umdf\2.15;$(ProjectDir)..\..\Common\Include;$(WindowsSdkDir)Include\$(WindowsTargetPlatformVersion)\um\iddcx\$(IDDCX_VERSION_MAJOR).$(IDDCX_VERSION_MINOR);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;setupapi.lib</AdditionalDependencies>
</Link>
<DriverSign>
<FileDigestAlgorithm>SHA256</FileDigestAlgorithm>
@@ -291,7 +289,7 @@
<EnablePREfast>true</EnablePREfast>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;setupapi.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
@@ -303,7 +301,7 @@
<EnablePREfast>true</EnablePREfast>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;setupapi.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
@@ -314,11 +312,11 @@
<ExceptionHandling>Async</ExceptionHandling>
<EnablePREfast>true</EnablePREfast>
<AdditionalOptions>/D_ATL_NO_WIN_SUPPORT /DUMDF_DRIVER /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=4 /DIDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\Common\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(WindowsSdkDir)Include\wdf\umdf\$(UMDF_VERSION_MAJOR).$(UMDF_VERSION_MINOR);$(WindowsSdkDir)Include\$(WindowsTargetPlatformVersion)\wdf\umdf\$(UMDF_VERSION_MAJOR).$(UMDF_VERSION_MINOR);$(ProjectDir)..\..\ThirdParty\Windows-Driver-Frameworks\src\publicinc\wdf\umdf\2.15;$(ProjectDir)..\..\Common\Include;$(WindowsSdkDir)Include\$(WindowsTargetPlatformVersion)\um\iddcx\$(IDDCX_VERSION_MAJOR).$(IDDCX_VERSION_MINOR);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;setupapi.lib</AdditionalDependencies>
</Link>
<DriverSign>
<FileDigestAlgorithm>SHA1</FileDigestAlgorithm>
@@ -338,10 +336,11 @@
<ExceptionHandling>Async</ExceptionHandling>
<EnablePREfast>true</EnablePREfast>
<AdditionalOptions>/D_ATL_NO_WIN_SUPPORT /DUMDF_DRIVER /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=10 /DIDDCX_MINIMUM_VERSION_REQUIRED=3 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\Common\Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(WindowsSdkDir)Include\wdf\umdf\$(UMDF_VERSION_MAJOR).$(UMDF_VERSION_MINOR);$(WindowsSdkDir)Include\$(WindowsTargetPlatformVersion)\wdf\umdf\$(UMDF_VERSION_MAJOR).$(UMDF_VERSION_MINOR);$(ProjectDir)..\..\ThirdParty\Windows-Driver-Frameworks\src\publicinc\wdf\umdf\2.15;$(ProjectDir)..\..\Common\Include;$(WindowsSdkDir)Include\$(WindowsTargetPlatformVersion)\um\iddcx\$(IDDCX_VERSION_MAJOR).$(IDDCX_VERSION_MINOR);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;setupapi.lib</AdditionalDependencies>
</Link>
<DriverSign>
<FileDigestAlgorithm>SHA256</FileDigestAlgorithm>
@@ -1,4 +1,4 @@
<?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">
@@ -30,9 +30,6 @@
<ClInclude Include="Trace.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\Downloads\wudfwdm.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Driver.cpp">
+165 -96
View File
@@ -1,97 +1,166 @@
<?xml version='1.0' encoding='utf-8'?>
<vdd_settings>
<monitors>
<count>1</count>
</monitors>
<gpu>
<friendlyname>default</friendlyname>
</gpu>
<global>
<!--These are global refreshrates, any you add in here, will be replicated to all resolutions-->
<g_refresh_rate>60</g_refresh_rate>
<g_refresh_rate>90</g_refresh_rate>
<g_refresh_rate>120</g_refresh_rate>
<g_refresh_rate>144</g_refresh_rate>
<g_refresh_rate>165</g_refresh_rate>
<g_refresh_rate>244</g_refresh_rate>
</global>
<resolutions>
<resolution>
<width>800</width>
<height>600</height>
<refresh_rate>30</refresh_rate>
</resolution>
<resolution>
<width>1366</width>
<height>768</height>
<refresh_rate>30</refresh_rate>
</resolution>
<resolution>
<width>1920</width>
<height>1080</height>
<refresh_rate>30</refresh_rate>
</resolution>
<resolution>
<width>2560</width>
<height>1440</height>
<refresh_rate>30</refresh_rate>
</resolution>
<resolution>
<width>3840</width>
<height>2160</height>
<refresh_rate>30</refresh_rate>
</resolution>
</resolutions>
<logging>
<SendLogsThroughPipe>true</SendLogsThroughPipe> <!-- Can only send logs through pipe if logging is enabled-->
<logging>false</logging>
<!-- DEBUG LOGGING FOR EXPERTS ONLY!-->
<debuglogging>false</debuglogging>
<!-- DEBUG LOGS CAN GENERATE 1000+ LINES-->
<!-- Warning: Leaving logging on too long can lead to excessive filesize. Especially DebugLogging, which should only be used for short periods to log errors. -->
<!-- Logging: Useful to troubleshoot and determine which GPUs are being used, and if displays are working as intended.-->
<!-- Debug Logging: Logs local system information with every driver function/event/process. Useful for GitHub Help Tickets.-->
</logging>
<colour>
<SDR10bit>false</SDR10bit>
<HDRPlus>false</HDRPlus> <!-- If you have SDR10 bit enabled, HDRPlus wont work - there’s a conflict because the display system cannot simultaneously handle both high dynamic range 12-bit and standard dynamic range 10-bit settings. -->
<ColourFormat>RGB</ColourFormat>
<!--
Supported colour formats:
RGB
YCbCr444
YCbCr422
YCbCr420
Any invalid colour formats which are used will default to use RGB
-->
</colour>
<cursor>
<HardwareCursor>true</HardwareCursor>
<!--Whether to display a hardware cursor in the buffer (If disabled streaming apps will use client cursor)-->
<CursorMaxY>128</CursorMaxY>
<!--The maximum height support for all cursor types. Older intel cpus may be limited to 64x64 -->
<CursorMaxX>128</CursorMaxX>
<!--The maximum width supported for all supported cursor types.-->
<AlphaCursorSupport>true</AlphaCursorSupport>
<!--Indicates if the adapter supports the 32-bit alpha cursor format. Most cursors are alpha format.-->
<XorCursorSupportLevel>2</XorCursorSupportLevel>
<!-- Do not change if you don't know what you're doing -->
<!--
0 = IDDCX_XOR_CURSOR_SUPPORT_UNINITIALIZED
1 = IDDCX_XOR_CURSOR_SUPPORT_NONE
2 = IDDCX_XOR_CURSOR_SUPPORT_FULL
3 = IDDCX_XOR_CURSOR_SUPPORT_EMULATION
-->
</cursor>
<edid>
<CustomEdid>false</CustomEdid>
<!-- Custom Edid should be named "user_edid.bin"! This does not support emulating resolutions!-->
<PreventSpoof>false</PreventSpoof>
<!--Enable this to prevent manufacturer spoofing when using custom edid. Please only do so if you need to!-->
<EdidCeaOverride>false</EdidCeaOverride>
<!--Enable this to override or add hard coded cea-extension block to custom Edid support allowing you to enable HDR-->
</edid>
<?xml version='1.0' encoding='utf-8'?>
<!-- ===============================================================================
Virtual Display Driver (HDR) - Minimal Configuration File
Contains ONLY functional settings (unused settings removed)
Original file contained 63 settings, this minimal version contains 52 functional settings
Generated: August 16, 2025 based on driver code analysis
=============================================================================== -->
<vdd_settings>
<!-- === BASIC DRIVER CONFIGURATION === -->
<monitors>
<count>1</count>
</monitors>
<gpu>
<friendlyname>default</friendlyname>
</gpu>
<!-- === RESOLUTION CONFIGURATION === -->
<global>
<!-- Global refresh rates - applied to all resolutions -->
<g_refresh_rate>60</g_refresh_rate>
<g_refresh_rate>90</g_refresh_rate>
<g_refresh_rate>120</g_refresh_rate>
<g_refresh_rate>144</g_refresh_rate>
<g_refresh_rate>165</g_refresh_rate>
<g_refresh_rate>240</g_refresh_rate>
</global>
<resolutions>
<resolution>
<width>1920</width>
<height>1080</height>
<refresh_rate>60</refresh_rate>
</resolution>
<resolution>
<width>2560</width>
<height>1440</height>
<refresh_rate>60</refresh_rate>
</resolution>
<resolution>
<width>3840</width>
<height>2160</height>
<refresh_rate>60</refresh_rate>
</resolution>
</resolutions>
<!-- === LOGGING CONFIGURATION === -->
<logging>
<SendLogsThroughPipe>true</SendLogsThroughPipe>
<logging>false</logging>
<debuglogging>false</debuglogging> <!-- WARNING: Debug logging creates large files -->
</logging>
<!-- === COLOR FORMAT CONFIGURATION === -->
<colour>
<SDR10bit>false</SDR10bit>
<HDRPlus>false</HDRPlus>
<ColourFormat>RGB</ColourFormat> <!-- Options: RGB, YCbCr444, YCbCr422, YCbCr420 -->
</colour>
<!-- === CURSOR CONFIGURATION === -->
<cursor>
<HardwareCursor>true</HardwareCursor>
<CursorMaxX>128</CursorMaxX>
<CursorMaxY>128</CursorMaxY>
<AlphaCursorSupport>true</AlphaCursorSupport>
<!-- NOTE: XorCursorSupportLevel has implementation bug - loaded but not used -->
<XorCursorSupportLevel>2</XorCursorSupportLevel>
</cursor>
<!-- === CUSTOM EDID CONFIGURATION === -->
<edid>
<CustomEdid>false</CustomEdid> <!-- Use custom "user_edid.bin" file -->
<PreventSpoof>false</PreventSpoof> <!-- Prevent manufacturer ID spoofing -->
<EdidCeaOverride>false</EdidCeaOverride> <!-- Override CEA extension block -->
</edid>
<!-- === EDID INTEGRATION SYSTEM === -->
<edid_integration>
<enabled>false</enabled> <!-- DISABLED: Enable when you have monitor_profile.xml -->
<auto_configure_from_edid>false</auto_configure_from_edid> <!-- Auto-apply monitor_profile.xml -->
<edid_profile_path>EDID/monitor_profile.xml</edid_profile_path>
<override_manual_settings>false</override_manual_settings> <!-- false = manual settings take priority -->
<fallback_on_error>true</fallback_on_error> <!-- Use manual settings if EDID fails -->
</edid_integration>
<!-- === HDR CONFIGURATION === -->
<hdr_advanced>
<hdr10_static_metadata>
<enabled>false</enabled> <!-- DISABLED: Enable for HDR10 support -->
<max_display_mastering_luminance>1000.0</max_display_mastering_luminance>
<min_display_mastering_luminance>0.05</min_display_mastering_luminance>
<max_content_light_level>1000</max_content_light_level>
<max_frame_avg_light_level>400</max_frame_avg_light_level>
</hdr10_static_metadata>
<color_primaries>
<enabled>false</enabled> <!-- DISABLED: Enable for custom color primaries -->
<red_x>0.640</red_x> <!-- sRGB color space (safe defaults) -->
<red_y>0.330</red_y>
<green_x>0.300</green_x>
<green_y>0.600</green_y>
<blue_x>0.150</blue_x>
<blue_y>0.060</blue_y>
<white_x>0.3127</white_x> <!-- D65 white point -->
<white_y>0.3290</white_y>
</color_primaries>
<color_space>
<enabled>false</enabled> <!-- DISABLED: Enable for advanced gamma -->
<gamma_correction>2.2</gamma_correction> <!-- Standard sRGB gamma -->
<primary_color_space>sRGB</primary_color_space> <!-- Safe default: sRGB -->
<enable_matrix_transform>false</enable_matrix_transform>
</color_space>
</hdr_advanced>
<!-- === AUTO RESOLUTION SYSTEM === -->
<auto_resolutions>
<enabled>false</enabled> <!-- DISABLED: Enable for EDID mode generation -->
<source_priority>manual</source_priority> <!-- Use manual resolutions only by default -->
<edid_mode_filtering>
<min_refresh_rate>24</min_refresh_rate>
<max_refresh_rate>240</max_refresh_rate>
<exclude_fractional_rates>false</exclude_fractional_rates>
<min_resolution_width>640</min_resolution_width>
<min_resolution_height>480</min_resolution_height>
<max_resolution_width>7680</max_resolution_width>
<max_resolution_height>4320</max_resolution_height>
</edid_mode_filtering>
<preferred_mode>
<use_edid_preferred>false</use_edid_preferred> <!-- Use manual preferred mode -->
<fallback_width>1920</fallback_width>
<fallback_height>1080</fallback_height>
<fallback_refresh>60</fallback_refresh>
</preferred_mode>
</auto_resolutions>
<!-- === ADVANCED COLOR PROCESSING === -->
<color_advanced>
<bit_depth_management>
<auto_select_from_color_space>false</auto_select_from_color_space> <!-- Manual control -->
<force_bit_depth>8</force_bit_depth> <!-- Safe default: 8-bit -->
<fp16_surface_support>true</fp16_surface_support> <!-- Keep enabled for compatibility -->
</bit_depth_management>
<color_format_extended>
<!-- NOTE: wide_color_gamut and hdr_tone_mapping are loaded but not implemented -->
<sdr_white_level>80.0</sdr_white_level> <!-- Standard SDR white level -->
</color_format_extended>
</color_advanced>
<!-- === REMOVED SECTIONS ===
The following sections were present in the original vdd_settings.xml but have been
removed because they are loaded but never used in the driver:
1. monitor_emulation (8 settings) - All settings loaded but unused
- enabled, emulate_physical_dimensions, physical_width_mm, physical_height_mm
- manufacturer_emulation/enabled, manufacturer_name, model_name, serial_number
2. color_format_extended partial (2 settings) - Loaded but unused
- wide_color_gamut, hdr_tone_mapping
Driver uses hardcoded values instead of these XML settings.
=== -->
</vdd_settings>
@@ -0,0 +1,401 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
# but not Directory.Build.rsp, as it configures directory-level build defaults
!Directory.Build.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml
CLAUDE.md
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 MikeTheTech
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -0,0 +1,104 @@
<?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="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</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|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>
<Inf2CatUseLocalTime>true</Inf2CatUseLocalTime>
<EnableInf2cat>true</EnableInf2cat>
</PropertyGroup>
<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>
@@ -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>
@@ -0,0 +1,144 @@
> [!WARNING]
> This software is in beta and requires test signing to be enabled.
# Virtual Audio Driver by MikeTheTech
Welcome to the **Virtual Audio Driver by MikeTheTech**! This project provides two key drivers based on the Windows Driver Kit (WDK):
- **Virtual Audio Driver** – Creates a virtual speaker output device and a virtual microphone input device.
Both features in the driver are suitable for remote desktop sessions, headless configurations, streaming setups, and more. They support Windows 10 and Windows 11, including advanced audio features like Windows Sonic (Spatial Sound), Exclusive Mode, Application Priority, and volume control.
<div align="center">
<img src="https://github.com/user-attachments/assets/1e833f96-5565-4938-a242-b239074012b0" alt="image">
<img src="https://github.com/user-attachments/assets/db8c23f3-cf2d-409f-ada8-38d0aa8450a8" width="31%" alt="image">
<img src="https://github.com/user-attachments/assets/8cf14cc2-4ab0-41ad-a6b2-5a77b004a943" width="31%" alt="image">
<img src="https://github.com/user-attachments/assets/5f2e23cb-75d3-4557-98ff-7c717f47dcdd" width="31%" alt="image">
</div>
## Overview
A virtual audio driver set consists of:
- **Virtual Audio** ("fake" speaker output)
- Essential for headless servers, remote desktop streaming, testing audio in environments without physical speakers, etc.
- **Virtual Microphone** ("fake" mic input)
- Ideal for streaming setups, voice chat tests, combining or routing audio internally, or feeding software-generated audio to apps expecting a microphone input.
By installing these drivers, you can process or forward audio without physical hardware present, making them incredibly useful for various development, testing, and media production scenarios.
---
## Key Features
| Feature | Virtual Speaker | Virtual Microphone |
|----------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
| **Emulated Device** | Emulates a speaker device recognized by Windows. | Emulates a microphone device recognized by Windows. |
| **Supported Audio Formats** | **8-bit, 8000 Hz** (lowest quality) up to **32-bit, 192,000 Hz** (studio quality). This includes various presets such as Telephone Quality (8-bit, 11025 Hz) and DVD/Studio Quality (16/24/32-bit, up to 192 kHz). | **16-bit 44,100 Hz**, **16-bit 48,000 Hz**, **24-bit 96,000 Hz**, **24-bit 192,000 Hz**, **32-bit 48,000 Hz** (for testing or specialized scenarios). |
| **Spatial Sound Support** (Speaker Only) | Integrates with Windows Sonic, enabling immersive 3D audio features. | Integrated with Audio Enhancements such as Voice Focus and Background Noise Reduction. |
| **Exclusive Mode and App Priority** | Applications can claim exclusive control of the device. | Same WDK architecture applies, allowing exclusive access in supported workflows. |
| **Volume Level Handling** | Handles global and per-application volume changes (Windows mixer). | Microphone level adjustments accessible via Windows Sound Settings or audio software. |
| **High Customizability** | Built to be extended with future features and audio enhancements. | Allows flexible configuration of sampling rates and bit depths for specialized audio requirements. |
---
## Compatibility
- **OS**: Windows 10 (Build 1903 and above) and Windows 11
- **Architecture**: x64 (tested); ARM64
---
## Installation
1. **Enable Test Signing (Optional)**
If you have a test-signed driver, you may need to enable test signing mode:
```powershell
bcdedit /set testsigning on
```
*Note: A production-signed driver can skip this step.*
2. **Open Device Manager**
- Choose **Audio inputs and outputs**, then in the top **Action** menu, choose **Add Legacy Hardware**.
- Choose **Install the hardware that I manually select from a list (Advanced)**
- Choose **Sound, video and game controllers**
- Choose "Have Disk..." and locate the **VirtualAudioDriver.inf**
- Continue with the installation.
3. **Verify Installation**
- Open **Device Manager**.
- Check under **Sound, video and game controllers** for “Virtual Audio Driver” (speaker).
- Check under **Audio inputs and outputs** for “Virtual Mic Driver” (microphone).
---
## Usage
### Using the Virtual Speaker
1. **Select as Default Device**
- Open **Sound Settings** → **Output** → Choose “Virtual Audio Driver” as your default output device.
- Or use the **Volume Mixer** to route specific apps to the virtual speaker.
2. **Remote Desktop or Streaming**
- When initiating a remote desktop session, the virtual speaker device can appear as a valid playback device.
- Streaming or capture apps can detect the virtual speaker for capturing system audio.
3. **Choosing Quality Settings**
- In **Sound Settings**, under **Playback Devices**, right-click the “Virtual Audio Driver” and select **Properties** → **Advanced** tab.
- Choose from the newly added sample rates and bit depths (ranging from 8-bit, 8000 Hz to 32-bit, 192,000 Hz) to match your desired use case (e.g., “Telephone Quality,” “DVD Quality,” or “Studio Quality”).
4. **Spatial Sound**
- In **Sound Settings**, right-click the device, select **Properties** → **Spatial Sound** tab, and enable **Windows Sonic for Headphones** or another supported format.
### Using the Virtual Microphone
1. **Select as Default Recording Device**
- Open **Sound Settings** → **Input** → Choose “Virtual Mic Driver” as your default input device.
- Alternatively, in the **Volume Mixer** or your specific application’s audio settings, route or select the “Virtual Mic Driver” for input.
2. **Supported Formats**
- The Virtual Microphone Driver supports:
- **16-bit, 44,100 Hz**
- **16-bit, 48,000 Hz**
- **24-bit, 96,000 Hz**
- **24-bit, 192,000 Hz**
- **32-bit, 48,000 Hz**
3. **Use Cases**
- **Voice Chat / Conference Apps**: Emulate or inject audio into Zoom, Teams, Discord, etc.
- **Streaming / Broadcasting**: Feed application-generated audio to OBS, XSplit, or other streaming tools.
- **Audio Testing**: Confirm that your software or game engine’s microphone-handling logic works without real hardware.
4. **Volume & Level Controls**
- Adjust input levels in **Sound Settings** → **Recording** tab.
- Per-app mic levels can be configured in certain software or system volume mixers (where supported).
---
## Configuration
- **Exclusive Mode** (Speaker and Mic)
By default, shared mode is enabled. For real-time, low-latency usage, open device properties, go to the **Advanced** tab, and uncheck “Allow applications to take exclusive control.”
- **Application Priority**
Supported through Windows APIs. To prioritize a specific application for either the speaker or microphone, configure it via Windows advanced sound options or in your audio software.
- **Volume/Level Management**
- For the Virtual Speaker, adjust in the main Sound Settings or the Volume Mixer.
- For the Virtual Microphone, adjust input levels in the Recording tab of Sound Settings or in your audio software’s device preferences.
---
## Future Plans
- **Advanced Diagnostics**: Logging and debugging tools
- **New Modes & Additional Formats**: Continued expansion of supported audio qualities.
- **Additional Features**: Such as Automatic Volume Leveling (AVL), further spatial audio improvements, and custom routing tools.
> This project is maintained and actively improved. We welcome contributions, suggestions, and issue reports!
---
**Thank you for using the Virtual Audio Driver!**
Feel free to open issues or submit pull requests if you encounter any problems or have ideas to share. Happy audio routing!
@@ -0,0 +1,200 @@
<?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="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</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)' == ''">x64</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>Windows Driver</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>Windows Driver</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>Windows Driver</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>Windows Driver</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>
<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>
<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>
<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>
@@ -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>
@@ -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 _VIRTUALAUDIODRIVER_MICARRAY1TOPTABLE_H_
#define _VIRTUALAUDIODRIVER_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 // _VIRTUALAUDIODRIVER_MICARRAY1TOPTABLE_H_
@@ -0,0 +1,824 @@
/*++
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
CMiniportTopologyVirtualAudioDriver::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 CMiniportTopologyVirtualAudioDriver::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 =
CMiniportTopologyVirtualAudioDriver::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_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()
@@ -0,0 +1,97 @@
/*++
Copyright (c) Microsoft Corporation All Rights Reserved
Module Name:
micarraytopo.h
Abstract:
Declaration of mic array topology miniport.
--*/
#ifndef _VIRTUALAUDIODRIVER_MICARRAYTOPO_H_
#define _VIRTUALAUDIODRIVER_MICARRAYTOPO_H_
#include "basetopo.h"
//=============================================================================
// Classes
//=============================================================================
///////////////////////////////////////////////////////////////////////////////
// CMicArrayMiniportTopology
//
#pragma code_seg()
class CMicArrayMiniportTopology :
public CMiniportTopologyVirtualAudioDriver,
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),
CMiniportTopologyVirtualAudioDriver(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 // _VIRTUALAUDIODRIVER_MICARRAYTOPO_H_
@@ -0,0 +1,489 @@
/*++
Copyright (c) Microsoft Corporation All Rights Reserved
Module Name:
micarraywavtable.h
Abstract:-
Declaration of wave miniport tables for the mic array.
--*/
#ifndef _VIRTUALAUDIODRIVER_MICARRAYWAVTABLE_H_
#define _VIRTUALAUDIODRIVER_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
//=============================================================================
// Extended array of supported device formats.
//=============================================================================
static
KSDATAFORMAT_WAVEFORMATEXTENSIBLE MicArrayPinSupportedDeviceFormats[] =
{
//------------------------------------------------------------------------
// 48 KHz, 32-bit, 2 channels (Stereo)
//------------------------------------------------------------------------
{
{
sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
0,
0,
0,
STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
},
{
{
WAVE_FORMAT_EXTENSIBLE, // wFormatTag
2, // nChannels
48000, // nSamplesPerSec
48000 * 2 * 4, // nAvgBytesPerSec = 48000 * channels * bytes_per_sample
2 * 4, // nBlockAlign = channels * bytes_per_sample
32, // wBitsPerSample
sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
},
32, // Samples (wValidBitsPerSample)
KSAUDIO_SPEAKER_STEREO, // dwChannelMask
STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
}
},
//------------------------------------------------------------------------
// 44.1 KHz, 16-bit, 2 channels (Stereo)
//------------------------------------------------------------------------
{
{
sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
0,
0,
0,
STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
},
{
{
WAVE_FORMAT_EXTENSIBLE,
2,
44100,
44100 * 2 * 2, // nAvgBytesPerSec = 44100 * channels * bytes_per_sample
2 * 2, // nBlockAlign = channels * bytes_per_sample
16,
sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
},
16, // wValidBitsPerSample
KSAUDIO_SPEAKER_STEREO,
STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
}
},
//------------------------------------------------------------------------
// 48 KHz, 16-bit, 2 channels (Stereo)
//------------------------------------------------------------------------
{
{
sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
0,
0,
0,
STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
},
{
{
WAVE_FORMAT_EXTENSIBLE,
2,
48000,
48000 * 2 * 2, // nAvgBytesPerSec = 48000 * channels * bytes_per_sample
2 * 2, // nBlockAlign = channels * bytes_per_sample
16,
sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
},
16,
KSAUDIO_SPEAKER_STEREO,
STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
}
},
//------------------------------------------------------------------------
// 96 KHz, 24-bit, 2 channels (Stereo)
//------------------------------------------------------------------------
{
{
sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
0,
0,
0,
STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
},
{
{
WAVE_FORMAT_EXTENSIBLE,
2,
96000,
96000 * 2 * 3, // nAvgBytesPerSec = 96000 * channels * bytes_per_sample
2 * 3, // nBlockAlign = channels * bytes_per_sample
24,
sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
},
24,
KSAUDIO_SPEAKER_STEREO,
STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
}
},
//------------------------------------------------------------------------
// 192 KHz, 24-bit, 2 channels (Stereo)
//------------------------------------------------------------------------
{
{
sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
0,
0,
0,
STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM),
STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
},
{
{
WAVE_FORMAT_EXTENSIBLE,
2,
192000,
192000 * 2 * 3, // nAvgBytesPerSec = 192000 * channels * bytes_per_sample
2 * 3, // nBlockAlign = channels * bytes_per_sample
24,
sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
},
24,
KSAUDIO_SPEAKER_STEREO,
STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM)
}
},
//------------------------------------------------------------------------
// Example: 48 KHz, 32-bit float, 2 channels (Stereo)
// Uses FLOAT subtype instead of PCM.
//------------------------------------------------------------------------
{
{
sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE),
0,
0,
0,
STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT),
STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)
},
{
{
WAVE_FORMAT_EXTENSIBLE,
2,
48000,
48000 * 2 * 4, // 4 bytes per float sample
2 * 4, // nBlockAlign
32, // wBitsPerSample
sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)
},
32,
KSAUDIO_SPEAKER_STEREO,
STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
}
},
};
//=============================================================================
// Supported modes (only on streaming pins).
// Add references to each format you want to expose in a particular mode.
//=============================================================================
static
MODE_AND_DEFAULT_FORMAT MicArrayPinSupportedDeviceModes[] =
{
// If you only have one signal processing mode (e.g., RAW),
// you can list each supported format under it.
{
STATIC_AUDIO_SIGNALPROCESSINGMODE_RAW,
&MicArrayPinSupportedDeviceFormats[0].DataFormat
},
{
STATIC_AUDIO_SIGNALPROCESSINGMODE_RAW,
&MicArrayPinSupportedDeviceFormats[1].DataFormat
},
{
STATIC_AUDIO_SIGNALPROCESSINGMODE_RAW,
&MicArrayPinSupportedDeviceFormats[2].DataFormat
},
{
STATIC_AUDIO_SIGNALPROCESSINGMODE_RAW,
&MicArrayPinSupportedDeviceFormats[3].DataFormat
},
{
STATIC_AUDIO_SIGNALPROCESSINGMODE_RAW,
&MicArrayPinSupportedDeviceFormats[4].DataFormat
},
{
STATIC_AUDIO_SIGNALPROCESSINGMODE_RAW,
&MicArrayPinSupportedDeviceFormats[5].DataFormat
},
};
//=============================================================================
// Notes on extension:
//
// 1. Adjust nChannels, nSamplesPerSec, wBitsPerSample, and the SUBTYPE_GUID
// as appropriate. For example, floating-point (IEEE_FLOAT) is common for
// advanced processing or higher-fidelity capture.
//
// 2. If you have multiple signal processing modes (like RAW, Speech, etc.),
// you may add new MODE_AND_DEFAULT_FORMAT entries pointing to different
// subsets of the MicArrayPinSupportedDeviceFormats array.
//
// 3. Make sure the size of KSDATAFORMAT_WAVEFORMATEXTENSIBLE (DataFormat.FormatSize)
// matches the actual structure size, and that WAVEFORMATEXTENSIBLE is
// used properly (e.g., wValidBitsPerSample must align with wBitsPerSample).
//
// 4. The GUID for KSDATAFORMAT_SUBTYPE_PCM or KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
// must be used correctly if you are advertising PCM or float formats.
//
// 5. KSAUDIO_SPEAKER_STEREO is a standard channel mask for 2 channels.
// If you have more channels (e.g., 4, 5.1, 7.1), use the appropriate
// speaker channel masks (e.g. KSAUDIO_SPEAKER_5POINT1).
//=============================================================================
//
// 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
VIRTUALAUDIODRIVER_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 // _VIRTUALAUDIODRIVER_MICARRAYWAVTABLE_H_
@@ -0,0 +1,177 @@
/*++
Copyright (c) Microsoft Corporation All Rights Reserved
Module Name:
minipairs.h
Abstract:
Local audio endpoint filter definitions.
--*/
#ifndef _VIRTUALAUDIODRIVER_MINIPAIRS_H_
#define _VIRTUALAUDIODRIVER_MINIPAIRS_H_
#include "speakertopo.h"
#include "speakertoptable.h"
#include "speakerwavtable.h"
#include "micarraytopo.h"
#include "micarray1toptable.h"
#include "micarraywavtable.h"
NTSTATUS
CreateMiniportWaveRTVirtualAudioDriver
(
_Out_ PUNKNOWN *,
_In_ REFCLSID,
_In_opt_ PUNKNOWN,
_In_ POOL_FLAGS,
_In_ PUNKNOWN,
_In_opt_ PVOID,
_In_ PENDPOINT_MINIPAIR
);
NTSTATUS
CreateMiniportTopologyVirtualAudioDriver
(
_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
CreateMiniportTopologyVirtualAudioDriver,
&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
CreateMiniportWaveRTVirtualAudioDriver,
&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
CreateMiniportWaveRTVirtualAudioDriver,
&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 // _VIRTUALAUDIODRIVER_MINIPAIRS_H_
@@ -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()
@@ -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 _VIRTUALAUDIODRIVER_SPEAKERTOPO_H_
#define _VIRTUALAUDIODRIVER_SPEAKERTOPO_H_
NTSTATUS PropertyHandler_SpeakerTopoFilter(_In_ PPCPROPERTY_REQUEST PropertyRequest);
NTSTATUS PropertyHandler_SpeakerTopology(_In_ PPCPROPERTY_REQUEST PropertyRequest);
#endif // _VIRTUALAUDIODRIVER_SPEAKERTOPO_H_
@@ -0,0 +1,206 @@
/*++
Copyright (c) Microsoft Corporation All Rights Reserved
Module Name:
speakertoptable.h
Abstract:
Declaration of topology tables.
--*/
#ifndef _VIRTUALAUDIODRIVER_SPEAKERTOPTABLE_H_
#define _VIRTUALAUDIODRIVER_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,
JACKDESC_RGB(0xB3,0xC9,0x8C), // 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 // _VIRTUALAUDIODRIVER_SPEAKERTOPTABLE_H_
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,184 @@
<?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="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</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)' == ''">x64</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>Windows Driver</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>Windows Driver</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>Windows Driver</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>Windows Driver</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>
<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>
<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>
<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>
@@ -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>
@@ -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_
@@ -0,0 +1,96 @@
/*++
Copyright (c) Microsoft Corporation All Rights Reserved
Module Name:
basetopo.h
Abstract:
Declaration of topology miniport.
--*/
#ifndef _VIRTUALAUDIODRIVER_BASETOPO_H_
#define _VIRTUALAUDIODRIVER_BASETOPO_H_
//=============================================================================
// Classes
//=============================================================================
///////////////////////////////////////////////////////////////////////////////
// CMiniportTopologyVirtualAudioDriver
//
class CMiniportTopologyVirtualAudioDriver
{
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:
CMiniportTopologyVirtualAudioDriver(
_In_ PCFILTER_DESCRIPTOR *FilterDesc,
_In_ USHORT DeviceMaxChannels
);
~CMiniportTopologyVirtualAudioDriver();
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
@@ -0,0 +1,477 @@
/*++
Copyright (c) Microsoft Corporation All Rights Reserved
Module Name:
Common.h
Abstract:
CAdapterCommon class declaration.
--*/
#ifndef _VIRTUALAUDIODRIVER_COMMON_H_
#define _VIRTUALAUDIODRIVER_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 _VIRTUALAUDIODRIVER_DEVPROPERTY {
const DEVPROPKEY *PropertyKey;
DEVPROPTYPE Type;
ULONG BufferSize;
__field_bcount_opt(BufferSize) PVOID Buffer;
} VIRTUALAUDIODRIVER_DEVPROPERTY, PVIRTUALAUDIODRIVER_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 VIRTUALAUDIODRIVER.<TopoName>.szPname in the inf's [Strings] section
PWSTR TemplateTopoName; // optional template name
PFNCREATEMINIPORT TopoCreateCallback;
PCFILTER_DESCRIPTOR* TopoDescriptor;
ULONG TopoInterfacePropertyCount;
const VIRTUALAUDIODRIVER_DEVPROPERTY* TopoInterfaceProperties;
// Wave RT miniport.
PWSTR WaveName; // make sure this or the template name matches with VIRTUALAUDIODRIVER.<WaveName>.szPname in the inf's [Strings] section
PWSTR TemplateWaveName; // optional template name
PFNCREATEMINIPORT WaveCreateCallback;
PCFILTER_DESCRIPTOR* WaveDescriptor;
ULONG WaveInterfacePropertyCount;
const VIRTUALAUDIODRIVER_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 VIRTUALAUDIODRIVER_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 //_VIRTUALAUDIODRIVER_COMMON_H_
@@ -0,0 +1,198 @@
/*++
Copyright (c) Microsoft Corporation All Rights Reserved
Module Name:
Definitions.h
Abstract:
Header file for common stuff.
--*/
#ifndef _VIRTUALAUDIODRIVER_DEFINITIONS_H_
#define _VIRTUALAUDIODRIVER_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_VIRTUALAUDIODRIVER\
0x836ba6d1, 0x3ff7, 0x4411, 0x8b, 0xcd, 0x46, 0x95, 0x53, 0x45, 0x2d, 0xce
DEFINE_GUIDSTRUCT("836BA6D1-3FF7-4411-8BCD-469553452DCE", PID_VIRTUALAUDIODRIVER);
#define PID_VIRTUALAUDIODRIVER DEFINE_GUIDNAMED(PID_VIRTUALAUDIODRIVER)
// Pool tag used for VIRTUALAUDIODRIVER allocations
#define VIRTUALAUDIODRIVER_POOLTAG 'SASM'
// Debug module name
#define STR_MODULENAME "VIRTUALAUDIODRIVER: "
// 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 // _VIRTUALAUDIODRIVER_DEFINITIONS_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 _VIRTUALAUDIODRIVER_ENDPOINTS_H_
#define _VIRTUALAUDIODRIVER_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 // _VIRTUALAUDIODRIVER_ENDPOINTS_H_
@@ -0,0 +1,159 @@
/*++
Copyright (c) Microsoft Corporation All Rights Reserved
Module Name:
kshelper.h
Abstract:
Helper functions for simple audio sample
--*/
#ifndef _VIRTUALAUDIODRIVER_KSHELPER_H_
#define _VIRTUALAUDIODRIVER_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
VirtualAudioDriverPropertyDispatch
(
_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
// VirtualAudioDriverPropertyDispatch.
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
} VIRTUALAUDIODRIVER_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 // _VIRTUALAUDIODRIVER_KSHELPER_H_
@@ -0,0 +1,81 @@
/*++
Copyright (c) Microsoft Corporation All Rights Reserved
Module Name:
minitopo.h
Abstract:
Declaration of topology miniport.
--*/
#ifndef _VIRTUALAUDIODRIVER_MINTOPO_H_
#define _VIRTUALAUDIODRIVER_MINTOPO_H_
#include "basetopo.h"
//=============================================================================
// Classes
//=============================================================================
///////////////////////////////////////////////////////////////////////////////
// CMiniportTopology
//
class CMiniportTopology :
public CMiniportTopologyVirtualAudioDriver,
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),
CMiniportTopologyVirtualAudioDriver(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 // _VIRTUALAUDIODRIVER_MINTOPO_H_
@@ -0,0 +1,336 @@
<?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="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</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>{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)' == ''">x64</Platform>
<SampleGuid>{2A9A946E-F017-4E0D-BF75-AD81E7E97D64}</SampleGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>False</UseDebugLibraries>
<DriverTargetPlatform>Windows Driver</DriverTargetPlatform>
<DriverType>KMDF</DriverType>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>False</UseDebugLibraries>
<DriverTargetPlatform>Windows Driver</DriverTargetPlatform>
<DriverType>KMDF</DriverType>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
</PropertyGroup>
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>True</UseDebugLibraries>
<DriverTargetPlatform>Windows Driver</DriverTargetPlatform>
<DriverType>KMDF</DriverType>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</ConfigurationType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<TargetVersion>Windows10</TargetVersion>
<UseDebugLibraries>True</UseDebugLibraries>
<DriverTargetPlatform>Windows Driver</DriverTargetPlatform>
<DriverType>KMDF</DriverType>
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
<ConfigurationType>Driver</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>
<ItemGroup Label="WrappedTaskItems" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Link>
<AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\portcls.lib;$(DDK_LIB_PATH)\stdunk.lib;$(DDK_LIB_PATH)\libcntpr.lib</AdditionalDependencies>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
</ResourceCompile>
<ClCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<TreatWarningAsError>true</TreatWarningAsError>
<WarningLevel>Level4</WarningLevel>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
</ClCompile>
<Midl>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<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>
<AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\portcls.lib;$(DDK_LIB_PATH)\stdunk.lib;$(DDK_LIB_PATH)\libcntpr.lib</AdditionalDependencies>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
</ResourceCompile>
<ClCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<TreatWarningAsError>true</TreatWarningAsError>
<WarningLevel>Level4</WarningLevel>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
</ClCompile>
<Midl>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<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>
<AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\portcls.lib;$(DDK_LIB_PATH)\stdunk.lib;$(DDK_LIB_PATH)\libcntpr.lib</AdditionalDependencies>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
</ResourceCompile>
<ClCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<TreatWarningAsError>true</TreatWarningAsError>
<WarningLevel>Level4</WarningLevel>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
</ClCompile>
<Midl>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<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>
<AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\portcls.lib;$(DDK_LIB_PATH)\stdunk.lib;$(DDK_LIB_PATH)\libcntpr.lib</AdditionalDependencies>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
</ResourceCompile>
<ClCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<TreatWarningAsError>true</TreatWarningAsError>
<WarningLevel>Level4</WarningLevel>
<PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN32;UNICODE;_UNICODE;PC_IMPLEMENTATION</PreprocessorDefinitions>
<PreprocessorDefinitions>%(PreprocessorDefinitions);DEBUG_LEVEL=DEBUGLVL_TERSE</PreprocessorDefinitions>
</ClCompile>
<Midl>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..</AdditionalIncludeDirectories>
<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>VirtualAudioDriver</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<TargetName>VirtualAudioDriver</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<TargetName>VirtualAudioDriver</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<TargetName>VirtualAudioDriver</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Link>
<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
Note that the single-component/multi-state feature requires also a registry
value set via the INF. The name of the registry value is SingleComponentMultiFxStates.
see INF file for more info.
-->
<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_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
</Midl>
<ResourceCompile>
<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);.\..\Utilities\$(IntDir)\Utilities.lib</AdditionalDependencies>
</Link>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);.\..\Filters\$(IntDir)\Filters.lib</AdditionalDependencies>
</Link>
<ClCompile>
<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_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
</Midl>
<ResourceCompile>
<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);.\..\Utilities\$(IntDir)\Utilities.lib</AdditionalDependencies>
</Link>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);.\..\Filters\$(IntDir)\Filters.lib</AdditionalDependencies>
</Link>
<ClCompile>
<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_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
</Midl>
<ResourceCompile>
<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);.\..\Utilities\$(IntDir)\Utilities.lib</AdditionalDependencies>
</Link>
<Link>
<AdditionalDependencies>%(AdditionalDependencies);.\..\Filters\$(IntDir)\Filters.lib</AdditionalDependencies>
</Link>
<ClCompile>
<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_;_USE_IPortClsRuntimePower</PreprocessorDefinitions>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Utilities</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Filters</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\Inc</AdditionalIncludeDirectories>
</Midl>
<ResourceCompile>
<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="common.cpp" />
<ClCompile Include="mintopo.cpp" />
<ClCompile Include="minwavert.cpp" />
<ClCompile Include="minwavertstream.cpp" />
<ClCompile Include="newdelete.cpp" />
<ResourceCompile Include="VirtualAudioDriver.rc" />
</ItemGroup>
<ItemGroup>
<Inf Exclude="@(Inx)" Include="*.inx" />
<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>
@@ -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="VirtualAudioDriver.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>
@@ -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, VIRTUALAUDIODRIVER_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, VIRTUALAUDIODRIVER_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, VIRTUALAUDIODRIVER_POOLTAG);
}
}
/*****************************************************************************
* ::delete()
*****************************************************************************
* Array Delete function.
*/
void __cdecl operator delete[]
(
_Pre_maybenull_ __drv_freesMem(Mem) PVOID pVoid
)
{
if (pVoid)
{
ExFreePoolWithTag(pVoid, VIRTUALAUDIODRIVER_POOLTAG);
}
}
#endif//_NEW_DELETE_OPERATORS_
@@ -0,0 +1,28 @@
/*++
Copyright (c) Microsoft Corporation All Rights Reserved
Module Name:
VirtualAudioDriver.rc
Abstract:
--*/
#include <windows.h>
#include <ntverp.h>
#define VER_FILETYPE VFT_DRV
#define VER_FILESUBTYPE VFT2_DRV_SOUND
#define VER_FILEDESCRIPTION_STR "Microsoft Virtual Simple Audio Sample Driver"
#define VER_INTERNALNAME_STR "VirtualAudioDriver.sys"
#define VER_ORIGINALFILENAME_STR "VirtualAudioDriver.sys"
#define VER_LEGALCOPYRIGHT_YEARS "2013"
#define VER_LEGALCOPYRIGHT_STR "Copyright (C) Microsoft Corp." VER_LEGALCOPYRIGHT_YEARS
#include "common.ver"
@@ -0,0 +1,845 @@
/*++
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 not saved to a file by default. Use the registry value
// DoNotCreateDataFiles (DWORD) = 0 to override this default.
//
DWORD g_DoNotCreateDataFiles = 1; // default is off.
DWORD g_DisableToneGenerator = 1; // default is to not 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()
{
PAGED_CODE();
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;
PDRIVER_OBJECT DriverObject;
HANDLE DriverKey;
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();
UNREFERENCED_PARAMETER(RegistryPath);
DriverObject = WdfDriverWdmGetDriverObject(WdfGetDriver());
DriverKey = NULL;
ntStatus = IoOpenDriverRegistryKey(DriverObject,
DriverRegKeyParameters,
KEY_READ,
0,
&DriverKey);
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
ntStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
(PCWSTR) DriverKey,
&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));
if (DriverKey)
{
ZwClose(DriverKey);
}
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);
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);
//
// Get registry configuration.
//
ntStatus = GetRegistrySettings(RegistryPathName);
IF_FAILED_ACTION_JUMP(
ntStatus,
DPF(D_ERROR, ("Registry Configuration error 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()
@@ -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")
CMiniportTopologyVirtualAudioDriver::CMiniportTopologyVirtualAudioDriver
(
_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;
} // CMiniportTopologyVirtualAudioDriver
CMiniportTopologyVirtualAudioDriver::~CMiniportTopologyVirtualAudioDriver
(
void
)
/*++
Routine Description:
Topology miniport destructor
Arguments:
Return Value:
void
--*/
{
PAGED_CODE();
DPF_ENTER(("[%s]",__FUNCTION__));
SAFE_RELEASE(m_AdapterCommon);
SAFE_RELEASE(m_PortEvents);
} // ~CMiniportTopologyVirtualAudioDriver
//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CMiniportTopologyVirtualAudioDriver::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
CMiniportTopologyVirtualAudioDriver::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
CMiniportTopologyVirtualAudioDriver::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(("[CMiniportTopologyVirtualAudioDriver::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
CMiniportTopologyVirtualAudioDriver::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
CMiniportTopologyVirtualAudioDriver::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
CMiniportTopologyVirtualAudioDriver::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
CMiniportTopologyVirtualAudioDriver::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
CMiniportTopologyVirtualAudioDriver::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(("[CMiniportTopologyVirtualAudioDriver::GenerateEventList]"));
ASSERT(m_PortEvents != NULL);
m_PortEvents->GenerateEventList(
Set,
EventId,
PinEvent,
PinId,
NodeEvent,
NodeId);
}
#pragma code_seg()
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,557 @@
/*++
Copyright (c) Microsoft Corporation All Rights Reserved
Module Name:
mintopo.cpp
Abstract:
Implementation of topology miniport.
--*/
#pragma warning (disable : 4127)
#include "definitions.h"
#include "endpoints.h"
#include "minwavert.h"
#include "mintopo.h"
//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CreateMiniportTopologyVirtualAudioDriver
(
_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 -
PoolType -
UnknownOuter -
DeviceContext -
MiniportPair -
Return Value:
NT status code.
--*/
{
PAGED_CODE();
UNREFERENCED_PARAMETER(UnknownAdapter);
ASSERT(Unknown);
ASSERT(MiniportPair);
CMiniportTopology *obj =
new (PoolFlags, MINWAVERT_POOLTAG)
CMiniportTopology( UnknownOuter,
MiniportPair->TopoDescriptor,
MiniportPair->DeviceMaxChannels,
MiniportPair->DeviceType,
DeviceContext );
if (NULL == obj)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
obj->AddRef();
*Unknown = reinterpret_cast<IUnknown*>(obj);
return STATUS_SUCCESS;
} // CreateMiniportTopologyVirtualAudioDriver
//=============================================================================
#pragma code_seg("PAGE")
CMiniportTopology::~CMiniportTopology
(
void
)
/*++
Routine Description:
Topology miniport destructor
Arguments:
Return Value:
NT status code.
--*/
{
PAGED_CODE();
DPF_ENTER(("[CMiniportTopology::~CMiniportTopology]"));
} // ~CMiniportTopology
//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CMiniportTopology::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.
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
CMiniportTopologyVirtualAudioDriver::DataRangeIntersection
(
PinId,
ClientDataRange,
MyDataRange,
OutputBufferLength,
ResultantFormat,
ResultantFormatLength
);
} // DataRangeIntersection
//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP
CMiniportTopology::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 CMiniportTopologyVirtualAudioDriver::GetDescription(OutFilterDescriptor);
} // GetDescription
//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP
CMiniportTopology::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(("[CMiniportTopology::Init]"));
NTSTATUS ntStatus;
ntStatus =
CMiniportTopologyVirtualAudioDriver::Init
(
UnknownAdapter,
Port_
);
IF_FAILED_ACTION_JUMP(
ntStatus,
DPF(D_ERROR, ("Init: CMiniportTopologyVirtualAudioDriver::Init failed, 0x%x", ntStatus)),
Done);
Done:
return ntStatus;
} // Init
//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP
CMiniportTopology::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
//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CMiniportTopology::PropertyHandlerJackDescription
(
_In_ PPCPROPERTY_REQUEST PropertyRequest,
_In_ ULONG cJackDescriptions,
_In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION * JackDescriptions
)
/*++
Routine Description:
Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION )
Arguments:
PropertyRequest -
cJackDescriptions - # of elements in the jack descriptions array.
JackDescriptions - Array of jack descriptions pointers.
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 < 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;
}
//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
CMiniportTopology::PropertyHandlerJackDescription2
(
_In_ PPCPROPERTY_REQUEST PropertyRequest,
_In_ ULONG cJackDescriptions,
_In_reads_(cJackDescriptions) PKSJACK_DESCRIPTION * JackDescriptions,
_In_ DWORD JackCapabilities
)
/*++
Routine Description:
Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION2 )
Arguments:
PropertyRequest -
cJackDescriptions - # of elements in the jack descriptions array.
JackDescriptions - Array of jack descriptions pointers.
JackCapabilities - Jack capabilities flags.
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 < 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 = JackCapabilities;
ntStatus = STATUS_SUCCESS;
}
}
}
}
}
return ntStatus;
}
//=============================================================================
#pragma code_seg("PAGE")
NTSTATUS
PropertyHandler_Topology
(
_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_Topology]"));
// PropertryRequest structure is filled by portcls.
// MajorTarget is a pointer to miniport object for miniports.
//
return
((PCMiniportTopology)
(PropertyRequest->MajorTarget))->PropertyHandlerGeneric
(
PropertyRequest
);
} // PropertyHandler_Topology
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,250 @@
/*++
Copyright (c) Microsoft Corporation All Rights Reserved
Module Name:
minwavert.h
Abstract:
Definition of wavert miniport class.
--*/
#ifndef _VIRTUALAUDIODRIVER_MINWAVERT_H_
#define _VIRTUALAUDIODRIVER_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 CMiniportTopologyVirtualAudioDriver;
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()
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 // _VIRTUALAUDIODRIVER_MINWAVERT_H_
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,196 @@
/*++
Copyright (c) Microsoft Corporation All Rights Reserved
Module Name:
minwavertstream.h
Abstract:
Definition of wavert miniport class.
--*/
#ifndef _VIRTUALAUDIODRIVER_MINWAVERTSTREAM_H_
#define _VIRTUALAUDIODRIVER_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:
//presentation
NTSTATUS GetPresentationPosition
(
_Out_ KSAUDIO_PRESENTATION_POSITION *_pPresentationPosition
);
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 // _VIRTUALAUDIODRIVER_MINWAVERTSTREAM_H_
@@ -0,0 +1,290 @@
/*++
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, VIRTUALAUDIODRIVER_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;
}
/* Use __analysis_assume to suppress the reports of a false OACR error. */
for(ULONG i = 0; i < m_ChannelCount; ++i)
{
if (m_BitsPerSample == 8)
{
__analysis_assume((DWORD)m_ChannelCount == FrameSize);
unsigned char *dataBuffer = reinterpret_cast<unsigned char *>(Frame);
dataBuffer[i] = ConvertToUChar(sinValue);
}
else if (m_BitsPerSample == 16)
{
__analysis_assume((DWORD)(m_ChannelCount) * 2 == FrameSize);
short *dataBuffer = reinterpret_cast<short *>(Frame);
dataBuffer[i] = ConvertToShort(sinValue);
}
else if (m_BitsPerSample == 24)
{
__analysis_assume((DWORD)(m_ChannelCount) * 3 == FrameSize);
BYTE *dataBuffer = Frame;
long val = ConvertToLong(sinValue);
val = val >> 8;
RtlCopyMemory(dataBuffer, &val, 3);
}
else if (m_BitsPerSample == 32)
{
__analysis_assume((DWORD)(m_ChannelCount) * 4 == FrameSize);
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,
VIRTUALAUDIODRIVER_POOLTAG);
IF_TRUE_ACTION_JUMP(m_PartialFrame == NULL, status = STATUS_INSUFFICIENT_RESOURCES, Done);
status = STATUS_SUCCESS;
Done:
return status;
}
@@ -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 _VIRTUALAUDIODRIVER_TONEGENERATOR_H
#define _VIRTUALAUDIODRIVER_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 // _VIRTUALAUDIODRIVER_TONEGENERATOR_H
@@ -0,0 +1,202 @@
<?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="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</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)' == ''">x64</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>Windows Driver</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>Windows Driver</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>Windows Driver</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>Windows Driver</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>
<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>
<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>
<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>
@@ -0,0 +1,31 @@
<?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>{CDBBEDA3-98E9-4C7A-BDB1-25EC47D0B087}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
<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>{CB830E4F-01DA-4D35-9789-E7DB0D02A79C}</UniqueIdentifier>
</Filter>
<Filter Include="Driver Files">
<Extensions>inf;inv;inx;mof;mc;</Extensions>
<UniqueIdentifier>{49F92783-3B39-4D0C-A153-8C346F754749}</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>
@@ -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"
//=============================================================================
// CVirtualAudioDriverHW
//=============================================================================
//=============================================================================
#pragma code_seg("PAGE")
CVirtualAudioDriverHW::CVirtualAudioDriverHW()
: m_ulMux(0),
m_bDevSpecific(FALSE),
m_iDevSpecific(0),
m_uiDevSpecific(0)
/*++
Routine Description:
Constructor for VirtualAudioDriverHW.
Arguments:
Return Value:
void
--*/
{
PAGED_CODE();
MixerReset();
} // VirtualAudioDriverHW
#pragma code_seg()
//=============================================================================
BOOL
CVirtualAudioDriverHW::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
CVirtualAudioDriverHW::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
CVirtualAudioDriverHW::iGetDevSpecific()
/*++
Routine Description:
Gets the HW (!) Device Specific info
Arguments:
N/A
Return Value:
int (in this example).
--*/
{
return m_iDevSpecific;
} // iGetDevSpecific
//=============================================================================
void
CVirtualAudioDriverHW::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
CVirtualAudioDriverHW::uiGetDevSpecific()
/*++
Routine Description:
Gets the HW (!) Device Specific info
Arguments:
N/A
Return Value:
UINT (in this example).
--*/
{
return m_uiDevSpecific;
} // uiGetDevSpecific
//=============================================================================
void
CVirtualAudioDriverHW::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
CVirtualAudioDriverHW::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
CVirtualAudioDriverHW::GetMixerMux()
/*++
Routine Description:
Return the current mux selection
Arguments:
Return Value:
ULONG
--*/
{
return m_ulMux;
} // GetMixerMux
//=============================================================================
LONG
CVirtualAudioDriverHW::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
CVirtualAudioDriverHW::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
CVirtualAudioDriverHW::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
CVirtualAudioDriverHW::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
CVirtualAudioDriverHW::SetMixerMux
(
_In_ ULONG ulNode
)
/*++
Routine Description:
Sets the HW (!) mux selection
Arguments:
ulNode - topology node id
Return Value:
void
--*/
{
m_ulMux = ulNode;
} // SetMixMux
//=============================================================================
void
CVirtualAudioDriverHW::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
@@ -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 _VIRTUALAUDIODRIVER_HW_H_
#define _VIRTUALAUDIODRIVER_HW_H_
//=============================================================================
// Defines
//=============================================================================
// BUGBUG we should dynamically allocate this...
#define MAX_TOPOLOGY_NODES 20
//=============================================================================
// Classes
//=============================================================================
///////////////////////////////////////////////////////////////////////////////
// CVirtualAudioDriverHW
// This class represents virtual Simple Audio Sample HW. An array representing volume
// registers and mute registers.
class CVirtualAudioDriverHW
{
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:
CVirtualAudioDriverHW();
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 CVirtualAudioDriverHW *PCVirtualAudioDriverHW;
#endif // _VIRTUALAUDIODRIVER_HW_H_
@@ -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
VirtualAudioDriverPropertyDispatch
(
_In_ PPCPROPERTY_REQUEST PropertyRequest
)
/*++
Handles and dispatches a VIRTUALAUDIODRIVER_PROPERTY_ITEM.
Use this as the property handler only if the property item is a
VIRTUALAUDIODRIVER_PROPERTY_ITEM.
--*/
{
PAGED_CODE();
VIRTUALAUDIODRIVER_PROPERTY_ITEM* item = (VIRTUALAUDIODRIVER_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
File diff suppressed because it is too large. Load diff
@@ -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 _VIRTUALAUDIODRIVER_SAVEDATA_H
#define _VIRTUALAUDIODRIVER_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
@@ -0,0 +1,91 @@
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|x64 = Debug|x64
Release|ARM64 = Release|ARM64
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|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|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|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|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|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|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|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|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|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|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
+31
View File
@@ -0,0 +1,31 @@
# VDD Utilities
This folder contains utility scripts to help manage the Virtual Display Driver.
## Toggle_VDD.bat
A menu-based batch script to easily enable/disable VDD without opening Device Manager.
### Features
- Real-time status display
- Enable/Disable VDD with one click
- Check detailed device information
- No external dependencies required
### Requirements
- Windows 10/11
- Administrator privileges
- PowerShell (built-in)
### Usage
1. Right-click `Toggle_VDD.bat` → Properties → Advanced
2. Check "Run as administrator" → OK
3. Double-click to run
### Menu Options
1. Enable VDD
2. Disable VDD
3. Check Status Only
4. Exit
Perfect for remote desktop users who frequently toggle VDD!
+23
View File
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<versions>
<release>
<name>Virtual Driver Control</name>
<build>25.7.22</build>
<link>https://github.com/yourusername/yourrepo/releases/download/v25.7.22/VirtualDriverControl-25.7.22.zip</link>
<description>Stable release with signed drivers and core functionality</description>
</release>
<beta>
<name>Virtual Driver Control</name>
<build>25.7.23</build>
<link>https://github.com/VirtualDrivers/Virtual-Display-Driver/releases/tag/25.7.23</link>
<description>Installer-less portable app with Install/Uninstall support, RELOAD_DRIVER functionality, officially signed drivers, and alpha XML Editor feature. Fixed Win 10 installation and RESTART_DRIVER issues.</description>
</beta>
<alpha>
<name>Virtual Driver Control</name>
<build>25.8.14</build>
<link>https://github.com/yourusername/yourrepo/releases/download/v25.7.24/VirtualDriverControl-25.7.24.zip</link>
<description>Development build with experimental features - for testing only</description>
</alpha>
</versions>