All Platforms
- git
- CMake 3.22 or later - the Windows build and the framework's own targets (interface/CMakeLists.txt, kernel/wdk/CMakeLists.txt); the configurations are debug and release, spelled so, on every platform (cmake --config, CMAKE_BUILD_TYPE, xcodebuild -configuration)
- doxygen for this documentation (doc/Doxyfile) - the repository's post-receive hook runs it on every push, its warnings show in the push output
macOS
- Xcode: the framework's interface/macOS/dx.xcodeproj (scheme dx) is referenced by a product's projects - the CoreAudio server plugin, the doorman daemon, the test app - built with xcodebuild; the deployment target is the product's
- signing and notarization: a Developer ID, the team id in the product's version.h (DX_TEAM_ID, which the binaries verify their own signature against in release), a notarytool keychain profile for the release pipeline (etc/release.sh: clone, build, pkgbuild/productbuild, notarization, publication, tag, version bump; --release stamps the versions final, releases the framework's commit from develop into main when it is none yet, merges the product's branch into main and raises the minor afterwards - every README.md naming the version ahead; --dryrun rehearses it in the clone without publishing or pushing)
- class compliant USB audio devices are owned by Apple's usbaudiod, which opens every audio interface's user client: a user mode driver reaches them only after a root process captured the device (dx_usb_capture.h, dx_daemon.h - the daemon a product installs as a launchd Mach service, its plist/daemon/launchd.plist and etc/daemon/postinstall)
macOS System Extensions
IOKit Kernel Extension Framework (legacy)
Kernel extensions can no longer be built or distributed; kernel/iokit stays for reference and is left out of this documentation. The notes that applied:
WDK - Windows Driver Kit
- Visual Studio 2022 or later with the C++ desktop workload; MSBuild is what CMake generates for and what builds the WiX projects
- the WDK and SDK come as NuGet packages: kernel/wdk/CMakeLists.txt names the version (WDK_VERSION) and restores Microsoft.Windows.WDK.<arch>, Microsoft.Windows.SDK.cpp.<arch> and Microsoft.Windows.SDK.cpp into ~/.nuget/packages when they are missing - no WDK installation, no Visual Studio driver extension; x64 and ARM64 (ARM64EC for user mode)
- WiX Toolset 6 as the NuGet SDK package the WiX projects reference (WixToolset.Sdk, WixToolset.UI.wixext) - MSBuild restores it, nothing is installed globally. DIFx is gone (deprecated by Microsoft, never ARM64, dropped by WiX 5): driver packages are installed by the product's install executable (dx::install::parser, dx_install.h) through SetupAPI, run as the .msi's custom actions
- etc/dxd_module.wxs: the product's merge module - the service, the ASIO driver, the install executable
- etc/dxd_installer.wxs: the .msi around it - the driver packages (a kernel package, a WinUSB package, or both with the choice DRIVER=portcls|winusb), their custom actions, the bus the service and the ASIO driver run on. A merge module's identifiers are modularized, which is why everything a command line property drives lives in the .msi
- etc/build.ps1: the release pipeline on Windows - every platform into build\<platform>, the module and the .msi into bin\<platform>\release; STAMPINF_VERSION (the product's version, off its version.h through etc/release.sh) stamps the infs (driver_package()) and versions the .msi; a local build stamps a time derived inf version. -Attest submits the driver packages of every platform in one submission once all are built, ahead of the installers, which then carry Microsoft's signature
- signing - etc/sign.ps1 does all of it, one signature primitive for every case: the EV certificate in an Azure key vault where the credentials stand (through AzureSignTool, which it installs itself where the machine has none), the machine's own certificate otherwise - -Subject names it, a self signed one for development or a company's own. Every configuration but debug takes a timestamp (-Config): a signature outlives its certificate only where one says when it was made
- development: -Prepare switches test signing on (bcdedit /set testsigning on, Secure Boot off in the firmware) and makes a self signed code signing certificate trusted as root and publisher; -Package <dir> signs a package's binaries, regenerates its catalog over them and signs that, -Symbols <dir> keeping the signed .sys/.pdb pair a crash dump needs. Installing belongs to the product's install executable (dx::install::parser, --install <inf>), which knows the device class and the hardware ids
- release: -Attest cabs the packages as they stand, of any architectures - one folder each, named <package>.<amd64|arm64> after its stamped inf, the .pdb among them, which Microsoft's crash analysis takes - signs the cab alone and submits it to the Hardware Dashboard (the cross signing of the past is gone since 2021), requesting the signatures the architectures take; Microsoft regenerates the catalogs and overwrites every embedded signature, so the cab's proves the company alone. What comes back replaces what was sent, -Bin <dir> putting it where the .msi build takes it. -File <files> is the Authenticode side: executables, dlls, the .msm/.msi
- the vault is named by AZURE_KEY_VAULT_URL and AZURE_KEY_VAULT_CERTIFICATE and reached either by AZURE_ACCESS_TOKEN - az account get-access-token --resource https://vault.azure.net, which leaves nothing secret on the machine - or by the service principal's AZURE_TENANT_ID, AZURE_CLIENT_ID and AZURE_CLIENT_SECRET; AZURE_DASHBOARD_TOKEN is the submission's own token. Each is a parameter as well- kernel logging: dxd::log/warnlog/errorlog reach the System event log at PASSIVE_LEVEL (the message resource dxd_log.mc, compiled into the driver), DbgPrint otherwise; DbgPrint is captured without a debugger through the NT kernel logger (logman start "NT Kernel Logger" -p "Windows Kernel Trace"
0x00040000 -o kdbg.etl -ets, tracerpt), the filter kernel/wdk/dxd_log.reg applies after a reboot
- a crash dump is read with cdb -z (the WinDbg store app) against the .sys/.pdb pair of the crashed build - keep the installed pair
- two machine kernel debug setup: enable debugging on the target
- to remove stale device entries in the device manager
devmgr_show_nonpresent_devices=1
- translation of user mode and kernel error error codes http://www.x86code.com/ntstatus.txt
Build server
- ssh server https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_keymanagement On the (virtual) machine, open an administrative PowerShell and run
# Install OpenSSH
Add-WindowsCapability -Online -Name OpenSSH.Server
# Set the sshd service to be started automatically.
Get-Service -Name sshd | Set-Service -StartupType Automatic -PassThru
# Start the sshd service.
Start-Service sshd
# Load your key files into ssh-agent.
ssh-add $env:USERPROFILE\.ssh\id_ecdsa
# make PowerShell default shell - etc/release.sh runs etc/build.ps1 there over ssh (wjob in etc/tools.sh)
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force
- non-admin build user
# Copy the public key file generated previously on your client to the authorized_keys file on your server.
Copy-Item $env:USERPROFILE\.ssh\id_ecdsa.pub $env:USERPROFILE\.ssh\authorized_keys
- administrator user (not recommended for build user)
# Copy the public key file generated previously on your client to the authorized_keys file on your server.
Copy-Item $env:USERPROFILE\.ssh\id_ecdsa.pub $env:ProgramData\ssh\administrators_authorized_keys
# fix ACLs
Icacls.exe $env:ProgramData\ssh\administrators_authorized_keys /inheritance:r /grant Administrators:F /grant SYSTEM:F
- everything else the machine needs: etc/bootstrap.ps1, run from a product's directory, reports what it does not install - Visual Studio with the C++ desktop workload, git, cmake - and installs what a signature takes: the .NET SDK, the Azure CLI as the msi (a remote session has no profile for an app package, so winget is no option there), AzureSignTool, the key vault and certificate the product's version.h names into the machine's environment, and the device code login of a session without a browser. From a Mac, etc/bootstrap.sh --server runs that same script over there - it starts the virtual machine and hands it to wjob, which maps the share and enters the product's directory, the way everything reaches that machine
cd <product> && ../dxd/etc/bootstrap.sh --server
- install your signing certs under the service "user" - Windows has no strict user concept
Tools
CoreAudio server plugin driver
- Installation
/Library/Audio/Plug-Ins/HAL
- stop CoreAudio server
sudo launchctl stop com.apple.audio.coreaudiod
- start CoreAudio server
sudo launchctl load com.apple.audio.coreaudiod
- debug CoreAudio Daemon by attaching to /usr/sbin/coreaudiod as root and wait for executable to be launched
- restart CoreAudio server
sudo launchctl stop com.apple.audio.coreaudiod && launchctl start com.apple.audio.coreaudiod
CoreMIDI client driver
CoreMIDI server plugin
- Installation
~/Library/Audio/MIDI Drivers
/Library/Audio/MIDI Drivers