Skip to content
/ APO Public

Some random notes about Windows Audio Processing Objects (APOs).

Notifications You must be signed in to change notification settings

dechamps/APO

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 

Repository files navigation

APO

Some random notes about Windows Audio Processing Objects (APOs) by Etienne Dechamps.

What is an APO?

APO stands for "Audio Processing Object". It is an API and framework designed by Microsoft for building pluggable audio filters (DSP). It is quite similar to VST in principle.

More technically, an APO takes the form of a COM class that implements the APO interfaces. The resulting class is typically provided as part of a DLL which is then registered in the system-wide COM registry (e.g. using regsvr32).

The class can then be instantiated, and each instance can process a continuous audio stream, making arbitrary changes to the audio data.

The Windows Audio Engine

What differentiates APOs from other audio filtering frameworks (such as VST) is that it is the filtering framework used by the Windows Audio Engine.

The Windows Audio Engine is a core component of the Windows audio stack. Its role is to bridge the gap between individual application audio streams and hardware audio devices. As such it handles various tasks such as mixing audio from multiple applications, automatic format conversions, etc.

Most application audio goes through the Windows Audio Engine. In particular it will process any audio stream that is opened through the WASAPI (Shared) API (and by extension DirectSound and MME, which use WASAPI Shared internally). The only exceptions are streams opened in WASAPI Exclusive mode, Kernel Streaming (WDM-KS), and native ASIO, which all bypass the Windows Audio Engine; but these are seldom used by typical applications.

The Windows Audio Engine uses a number of APOs internally as part of its normal operation, each handling a specific task such as automatic sample rate conversion. These internal APOs notably include the (in)famous CAudioLimiter.

APOs run inside the Windows audio graph process (audiodg.exe) which is itself managed by the Windows Audio service (audiosrv).

System effect APOs (sAPOs)

APOs can be installed as system effect APOs, or sAPOs, by implementing the IAudioSystemEffects interface. sAPOs are optional APOs that can be inserted at various points inside the Windows audio engine pipeline. sAPOs can be extremely useful because they can be used to arbitrarily filter audio for all Windows applications running system-wide; and because they run directly inside the Windows audio engine, they can do so in a very clean and efficient manner with no additional conversions and zero additional latency.

sAPOs can be positioned to filter audio data at the following stages of the Windows audio pipeline:

  • Stream Effect (SFX) APOs are instantiated for every application stream. They process the audio signal as it comes in and out of a single application.
    • In particular, in the playback direction, processing occurs before any mixing or sample rate conversion takes place.
    • SFX APOs are the only sAPOs that are allowed to change the channel count (i.e. downmix/upmix).
  • Mode Effect (MFX) APOs operate at an intermediate stage, on the mixed audio from all streams that share a common mode.
  • Endpoint Effect (EFX) APOs operate on the audio signal that comes in and out of the audio device.
    • In particular, in the playback direction, processing occurs after all mixing and sample rate conversion takes place (but before CAudioLimiter).

The above describes the modern sAPO architecture as it was introduced in Windows 8.1. Previously, different kinds of APOs were used:

  • Local Effect (LFX) APOs, also known as pre-mix APOs, serve the same purpose as SFX APOs.
  • Global Effect (GFX) APOs, also known as post-mix APOs, serve the same purpose as EFX APOs.

LFX and GFX APOs can still be used in modern versions of Windows, but Microsoft does not document them anymore; they should be considered deprecated. If both modern (SFX/MFX/EFX) and legacy (LFX/GFX) sAPOs are configured, then Windows will use the modern ones.

System effect APO installation

sAPOs are configured on a per-audio endpoint device basis. That is, each audio device uses its own set of APOs.

Which APOs to use is normally decided by the audio device driver; specifically, they are defined in the audio driver INF file.

An audio device driver can decide to use some of the sAPOs that are bundled with Windows, or it can implement its own custom sAPO and include it in the driver package. Keep in mind, however, that APOs always run in user mode (in the audiodg.exe process), not in kernel mode; they are merely bundled with the driver, and are not part of the kernel-mode driver module itself.

When an audio driver is installed, any custom sAPOs are installed and registered, and the sAPO configuration from its INF file is copied to the Windows Audio Engine configuration (see below).

After the audio driver is installed, it is technically possible to go in and change the Windows Audio Engine configuration after the fact to use different sAPOs, even third-party sAPOs that are not part of Windows nor the original driver. This is extremely powerful because that makes it possible to apply any arbitrary audio filtering to any audio device, independent of driver (think "system-wide VSTs"). This is precisely how Equalizer APO works. Note, however, that this approach to setting up sAPOs is not officially supported by Microsoft; the fact that it works should be considered an "happy accident". Also note that such custom configuration will be overwritten every time the audio driver is reinstalled, and that some Windows updates have a tendency to reinstall audio drivers.

Manipulating system effect APO configuration

All commands shown in this section are Powershell commands. Commands that make changes will only work when run as Administrator.

Location

The configuration for the Windows Audio Engine lives under the following Windows registry key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio

Playback devices are found under the Render key. Recording devices are found under the Capture key.

Under Render and Capture, each audio endpoint device has its own key, named after the endpoint GUID (see below).

Under each endpoint device key, the FxProperties key contains system effect APO configuration.

For example, the following key contains system effect APO configuration for the playback endpoint device with GUID {b39fc22d-4c5d-4e65-8276-db7f999d2d06}:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Render\{b39fc22d-4c5d-4e65-8276-db7f999d2d06}\FxProperties

The initial configuration comes from the driver store, which is itself populated from the audio device driver INF file.

Determining the GUID of an audio endpoint device

One way is to determine the GUID of an endpoint device is to open the Equalizer APO Configurator, select a device, and click on "Copy Device command to clipboard". The copied command includes the endpoint GUID.

Otherwise, you can use the following command:

Get-PnpDevice -Class AudioEndpoint | Format-Table -Property InstanceId,Present,FriendlyName

Example output:

FriendlyName                                                  Present InstanceId
------------                                                  ------- ----------
Headset (CORSAIR VIRTUOSO Wireless Gaming Headset)              False SWD\MMDEVAPI\{0.0.0.00000000}.{A8079308-1956-4FB7-BBB0-8D8842611102}
Headset Microphone (CORSAIR VIRTUOSO Wireless Gaming Headset)   False SWD\MMDEVAPI\{0.0.1.00000000}.{4ED8903D-2C88-4EAC-93E4-39B0BFE7475C}
Monitors (Xonar U7)                                              True SWD\MMDEVAPI\{0.0.0.00000000}.{5D16E8DA-37A3-4657-8D52-57FFE97F4EF9}
S/PDIF 1 (Virtual Audio Cable)                                  False SWD\MMDEVAPI\{0.0.1.00000000}.{42BA34C2-E6E7-452D-BCE3-ADCBEC30E1A4}
Line 1 (Virtual Audio Cable)                                    False SWD\MMDEVAPI\{0.0.0.00000000}.{185D6665-3115-45BD-9E85-39BA4E326DDD}

The InstanceId is normally SWD\MMDEVAPI\ followed by the endpoint ID string. The endpoint ID string is itself composed of a {0.0.0.00000000}. or {0.0.1.00000000}. prefix (denoting Render and Capture endpoints, respectively), followed by the endpoint GUID. So in the above example, Monitors is a Render endpoint device and its GUID is {5D16E8DA-37A3-4657-8D52-57FFE97F4EF9}.

Endpoint GUIDs will change if the audio driver is reinstalled. Note that some Windows updates reinstall all audio drivers as a side effect.

In code, the proper way to enumerate audio endpoints is to use IMMDeviceEnumerator::EnumAudioEndpoints().

FxProperties values

The FxProperties registry key holds the system effect APO configuration for a specific audio endpoint device.

The configuration is organized as a set of registry values, which correspond to individual properties. A property is identified by a GUID, followed by a comma ,, followed by a number. For example: {b725f130-47ef-101a-a5f1-02608c9eebac},10.

The official list of supported system effect APO properties can be found in the audio driver INF settings documentation (look for properties that are installed under HKR,FX\0 in the INF File Sample). Alternatively, the audioenginebaseapo.idl file in the Windows SDK contains a more exhaustive list (e.g. it includes legacy LFX/GFX properties).

The most important properties are those that control which sAPOs are used. These are:

Type Property ID Property name
SFX {d04e05a6-594b-4fb6-a80d-01af5eed7d1d},5 PKEY_FX_StreamEffectClsid
MFX {d04e05a6-594b-4fb6-a80d-01af5eed7d1d},6 PKEY_FX_ModeEffectClsid
EFX {d04e05a6-594b-4fb6-a80d-01af5eed7d1d},7 PKEY_FX_EndpointEffectClsid
LFX {d04e05a6-594b-4fb6-a80d-01af5eed7d1d},1 PKEY_FX_PreMixEffectClsid
GFX {d04e05a6-594b-4fb6-a80d-01af5eed7d1d},2 PKEY_FX_PostMixEffectClsid

If any of SFX, MFX or EFX are present, then LFX and GFX are ignored.

All properties are optional. If no properties are present, or if the FxProperties key is absent entirely, then no system effect APOs are used.

Another notable property is PKEY_AudioEndpoint_Disable_SysFx ({1da5d803-d492-4edd-8c23-e0c0ffee7f0e},5, DWORD), which, if set to 1, disables all sAPOs. It is mapped to the "Enable audio enhancements" checkbox in the Windows audio device settings.

Locating an sAPO

The string value of a PKEY_FX_*EffectClsid property is a CLSID which identifies the specific APO COM class to instantiate to filter the audio signal. CLSIDs are globally unique and chosen by the sAPO developer, so they can be expected to be stable even across different machines and OS versions.

When a sAPO is installed, it is registered in the system-wide COM class store found at HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID so that it can be looked up by its CLSID.

For example, the following command will look up information about CLSID {EC1CC9CE-FAED-4822-828A-82A81A6F018F} which is the Equalizer APO GFX sAPO:

$RegistryKey = Get-Item "HKLM:\SOFTWARE\Classes\CLSID\{EC1CC9CE-FAED-4822-828A-82A81A6F018F}"
$RegistryKey.GetValue("")
$RegistryKey.OpenSubKey("InprocServer32").GetValue("")

Example output:

EqualizerAPO Post-Mix Class
C:\Program Files\EqualizerAPO\EqualizerAPO.dll

In this example EqualizerAPO.dll is the DLL that contains the sAPO code. The Windows Audio engine audiodg.exe process will load that DLL to instantiate the filter and process the audio.

How to remove all sAPOs for an audio endpoint

The following example command will delete all registry values directly under FxProperties for the {2f716148-66dd-4afe-9698-d3c74eea039a} endpoint GUID, thus removing all sAPO configuration for that endpoint:

$RegistryKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey(
  "SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Render\{2f716148-66dd-4afe-9698-d3c74eea039a}\FxProperties",
  [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
  [System.Security.AccessControl.RegistryRights]::QueryValues -bor [System.Security.AccessControl.RegistryRights]::SetValue)
$RegistryKey.GetValueNames() | ForEach-Object { $RegistryKey.DeleteValue($_) }

You can use the Registry Editor to make a backup of the contents of the registry key before running the above command so that you can restore them later. Another way to revert to the default state is to reinstall the audio driver.

The same result can be achieved by deleting or renaming the FxProperties key, but permissions might get in the way (see below).

Registry permission issues

By default, special permissions apply to the overall MMDevices registry key. The only user with full control of that key is TrustedInstaller. Even Administrators have restricted permissions: they can add, modify and remove registry values, but they cannot change the keys.

This can prevent certain useful operations on the FxProperties key, such as deleting or renaming it, or even creating it in the first place (which is necessary in order to add sAPOs to an endpoint that never had any).

Fixing the permissions from the command line is surprisingly hard for a number of silly technical reasons. Namely: there is no easy way to run commands under the TrustedInstaller user or to enable the TakeOwnership privilege without the help of external tools, and built-in tools such as takeown cannot be used on the registry.

However, it is possible to fix the permissions manually using the Registry Editor (regedit):

  1. Navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio.
  2. Open the permissions of the Audio registry key and change its owner to the Administrators group.
  3. Give the Administrators group Full Control over the registry key.

You should then be able to make any change you like, including creating, deleting and renaming FxProperties keys.

Applying the changes

The relevant registry entries are consumed by the Windows Audio service (audiosrv). To make sure changes are picked up, the service usually needs to be restarted:

Restart-Service -Name audiosrv

Access rights, permissions, ACL issues when running APOs

As previously explained, APOs run inside the audiodg.exe process which itself runs under the Windows Audio Service (Audiosrv).

This service, like virtually all services, does not run under your normal Windows user account. Instead, its access token gives it permissions that are roughly equivalent to the LocalService account.

Most notably, for security and isolation reasons, the service does not have access to your user directory (i.e. C:\Users\<username>).

In some cases this can lead to an APO misbehaving because it is attempting to open a file (or other securable object, such as a registry key) that it is not allowed to access.

One example is attempting to store an Equalizer APO configuration file inside a user directory. The Equalizer APO Configuration Editor will display a helpful warning in this case, and the APO itself will log an error message into its logfile (C:\Windows\ServiceProfiles\LocalService\AppData\Local\Temp\EqualizerAPO.log).

In other cases the issue might be harder to troubleshoot. For example, most VSTs do not anticipate running into permission issues. When such VSTs are used inside Equalizer APO (for example) and run into unexpected access issues, the resulting behaviour can be erratic and hard to troubleshoot.

Troubleshooting access control issues

One way to confirm that an APO is having trouble accessing specific objects is to use Process Monitor. Use the following filters:

  • "Process Name" is audiodg.exe
  • "Result" is ACCESS DENIED

Then restart the Windows Audio service and start streaming audio. Access denied errors should then appear in Process Monitor.

The following example shows Equalizer APO attempting to open an inaccessible configuration file:

It is possible to determine which DLL is making the offending calls by looking at the event stack in Process Monitor. In this example it is EqualizerAPO.dll, as expected. If the failure originates from a VST used within Equalizer APO, the stack should mention the offending VST DLL alongside (or instead of) Equalizer APO.

Some issues can be more subtle. For example some VSTs might expect to find files or registry entries under the current user profile. These objects might exist under your personal user profile, but not in the local service user profile. To troubleshoot such issues you might need to widen your search and expand your Process Monitor filters to include more failure modes, such as "not found" errors.

Fixing access control issues

There are two ways to fix this issue:

  • Move the offending files/objects in a location that the Audio service can access. For example Program Files or ProgramData. Or:
  • Change the permissions (DACL) on the offending files/objects to allow access by the Audio service.

To adjust the permissions, go to the Security properties of the offending file/object (or a parent) and ensure the NT SERVICE\Audiosrv user principal has access. (This principal is the service SID. You can also use the local service account, but only allowing the Windows audio service is cleaner.)

Then restart the Windows Audio service.

Note: while this technique can be used to store Equalizer APO configuration files outside of the standard config directory, keep in mind that doing so will break the Equalizer APO "instant mode" feature (i.e. live changes) because Equalizer APO only watches its config directory for changes.

Useful links

About

Some random notes about Windows Audio Processing Objects (APOs).

Topics

Resources

Stars

Watchers

Forks