Skip to content

Commit

Permalink
Use the new PortAudio option to enable WASAPI Shared conversions.
Browse files Browse the repository at this point in the history
This feature was introduced in PortAudio commit
aa0748a5b59491ba2cfa9943825653cde6e1f748. It is enabled by default
since that makes WASAPI Shared much easier to use; it can be
disabled through the new FlexASIO wasapiAutoConvert option.

Fixes #32.
  • Loading branch information
dechamps committed Jun 23, 2019
1 parent c727ee9 commit 00cfda7
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 34 deletions.
32 changes: 11 additions & 21 deletions BACKENDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ wanting to optimize their audio pipeline. In particular, this document provides
the necessary information to understand what the [`backend`][backend] and
[`wasapiExclusiveMode`][wasapiExclusiveMode] FlexASIO configuration options do.

**Note:** this document is a work in progress, and does not go into much detail
regarding the specific differences between the backends. For now, you will have
to experiment for yourself. Comments and suggestions are welcome.

A `backend` is just another term for what PortAudio calls the *host API*.
FlexASIO uses the term "backend" to avoid potential confusion with the term
"ASIO host".
Expand Down Expand Up @@ -105,8 +101,9 @@ ms, if not more.
For example, it might expose 8 channels for a 5.1 output, downmixing the rear
channels pairs.

Modern versions of Windows implement the MME API by using WASAPI internally,
making this backend a "second-class citizen" compared to WASAPI and WDM-KS.
Modern versions of Windows implement the MME API by using WASAPI Shared
internally, making this backend a "second-class citizen" compared to WASAPI and
WDM-KS.

## DirectSound backend

Expand All @@ -122,7 +119,7 @@ if that's really the case in practice. The DirectSound backend has been observed
to [behave very poorly][issue29] with small buffer sizes on the input side,
making it a poor choice for low-latency capture use cases.

Modern versions of Windows implement the DirectSound API by using WASAPI
Modern versions of Windows implement the DirectSound API by using WASAPI Shared
internally, making this backend a "second-class citizen" compared to WASAPI and
WDM-KS.

Expand All @@ -147,16 +144,10 @@ used. The two modes behave very differently; in fact, they should probably be
seen as two separate backends entirely.

In *shared* mode, WASAPI behaves similarly to MME and DirectSound, in that the
audio goes through most of the normal Windows audio pipeline. One important
limitation of this mode is that there is no sample rate conversion. Therefore,
initialization will fail if the application sample rate is different from the
sample rate of the input or output devices, as configured in the Windows sound
settings. (Corollary: if the input and output devices are configured with
different sample rates in Windows, WASAPI Shared won't work, period.) There is
also no support for upmixing nor downmixing; the channel counts must match
exactly. These limitations [are inherent to WASAPI itself][wasapisr]. It is
reasonable to assume that this mode will provide the best possible latency for
a shared backend.
audio goes through most of the normal Windows audio pipeline. Indeed, in
modern versions of Windows, MME and DirectSound are just thin wrappers
implemented on top of WASAPI. For this reason it is reasonable to assume that
this mode will provide the best possible latency for a shared backend.

In *exclusive* mode, WASAPI behaves completely differently and bypasses the
entirety of the Windows audio pipeline, including mixing and APOs. As a result,
Expand Down Expand Up @@ -220,9 +211,8 @@ Streaming.
[wasapiExclusiveMode]: CONFIGURATION.md#option-wasapiExclusiveMode
[Windows Audio Session API]: https://docs.microsoft.com/en-us/windows/desktop/coreaudio/wasapi
[Windows Driver Model]: https://en.wikipedia.org/wiki/Windows_Driver_Model
[wasapisr]: https://docs.microsoft.com/windows/desktop/CoreAudio/device-formats
[WDM-KS issue]: https://github.com/dechamps/FlexASIO/issues/21

<!-- Use the converter at http://http://gravizo.com/ to recover the source code
of this graph. -->
[diagram]: https://g.gravizo.com/svg?digraph%20G%20%7B%0A%09rankdir%3D%22LR%22%0A%09style%3D%22dashed%22%0A%09fontname%3D%22sans-serif%22%0A%09node%5Bfontname%3D%22sans-serif%22%5D%0A%0A%09subgraph%20clusterApplicationProcess%20%7B%0A%09%09label%3D%22Application%20process%22%0A%0A%09%09Host%5Blabel%3D%22ASIO%20host%20application%22%5D%0A%0A%09%09subgraph%20clusterFlexASIO%20%7B%0A%09%09%09label%3D%22FlexASIO%22%0A%09%09%09FlexASIO%5Blabel%3D%22ASIO%20driver%22%5D%0A%0A%09%09%09subgraph%20clusterPortAudio%20%7B%0A%09%09%09%09label%3D%22PortAudio%22%0A%0A%09%09%09%09PortAudio%5Blabel%20%3D%20%22Frontend%22%5D%0A%09%09%09%09subgraph%20%7B%0A%09%09%09%09%09rank%3D%22same%22%0A%09%09%09%09%09node%20%5Bcolor%3D%22red%22%3B%20penwidth%3D3%5D%0A%0A%09%09%09%09%09PortAudioMME%5Blabel%3D%22MME%22%5D%0A%09%09%09%09%09PortAudioDirectSound%5Blabel%3D%22DirectSound%22%5D%0A%09%09%09%09%09PortAudioWASAPI%5Blabel%3D%22WASAPI%22%5D%0A%09%09%09%09%09PortAudioWDMKS%5Blabel%3D%22WDM-KS%22%5D%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%7D%0A%09%7D%0A%0A%09subgraph%20clusterWindows%20%7B%0A%09%09label%3D%22Windows%20audio%20subsystem%22%0A%09%09subgraph%20%7B%0A%09%09%09rank%3D%22same%22%0A%09%09%09MME%0A%09%09%09DirectSound%0A%09%09%09WASAPIShared%5Blabel%3D%22WASAPI%20(shared)%22%5D%0A%09%09%09WASAPIExclusive%5Blabel%3D%22WASAPI%20(exclusive)%22%5D%0A%09%09%09WDMKS%5Blabel%3D%22Kernel%20Streaming%22%5D%0A%09%09%7D%0A%0A%09%09SampleRateConversion%5Blabel%3D%22Sample%20rate%20conversion%22%5D%0A%09%09PreMix%5Blabel%3D%22Pre-mix%20APOs%22%5D%0A%09%09Mix%5Blabel%3D%22Mixing%22%5D%0A%09%09PostMix%5Blabel%3D%22Post-mix%20APOs%22%5D%0A%09%7D%0A%0A%09subgraph%20clusterHardware%20%7B%0A%09%09label%3D%22Audio%20hardware%22%0A%09%09HardwareDriver%5Blabel%3D%22Driver%22%5D%0A%09%09HardwareDevice%5Blabel%3D%22Device%22%5D%0A%09%7D%0A%0A%09Host-%3EFlexASIO%0A%09FlexASIO-%3EPortAudio%0A%0A%09PortAudio-%3E%7B%0A%09%09PortAudioMME%0A%09%09PortAudioDirectSound%0A%09%09PortAudioWASAPI%0A%09%09PortAudioWDMKS%0A%09%7D%0A%0A%09PortAudioMME-%3EMME%0A%09PortAudioDirectSound-%3EDirectSound%0A%09PortAudioWASAPI-%3EWASAPIShared%0A%09PortAudioWASAPI-%3EWASAPIExclusive%0A%09PortAudioWDMKS-%3EWDMKS%0A%0A%09MME-%3ESampleRateConversion%0A%09DirectSound-%3ESampleRateConversion%0A%09SampleRateConversion-%3EWASAPIShared%0A%09%0A%09WASAPIShared-%3EPreMix%0A%09WASAPIExclusive-%3EHardwareDriver%0A%09PreMix-%3EMix%0A%09Mix-%3EPostMix%0A%09PostMix-%3EHardwareDriver%0A%09%0A%09WDMKS-%3EHardwareDriver%0A%09%0A%09HardwareDriver-%3EHardwareDevice%0A%7D%0A
<!-- Use the converter at http://gravizo.com/ to recover the source code of this
graph. -->
[diagram]: https://g.gravizo.com/svg?digraph%20G%20%7B%0A%09rankdir%3D%22LR%22%0A%09style%3D%22dashed%22%0A%09fontname%3D%22sans-serif%22%0A%09node%5Bfontname%3D%22sans-serif%22%5D%0A%0A%09subgraph%20clusterApplicationProcess%20%7B%0A%09%09label%3D%22Application%20process%22%0A%0A%09%09Host%5Blabel%3D%22ASIO%20host%20application%22%5D%0A%0A%09%09subgraph%20clusterFlexASIO%20%7B%0A%09%09%09label%3D%22FlexASIO%22%0A%09%09%09FlexASIO%5Blabel%3D%22ASIO%20driver%22%5D%0A%0A%09%09%09subgraph%20clusterPortAudio%20%7B%0A%09%09%09%09label%3D%22PortAudio%22%0A%0A%09%09%09%09PortAudio%5Blabel%20%3D%20%22Frontend%22%5D%0A%09%09%09%09subgraph%20%7B%0A%09%09%09%09%09rank%3D%22same%22%0A%09%09%09%09%09node%20%5Bcolor%3D%22red%22%3B%20penwidth%3D3%5D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20PortAudioMME%5Blabel%3D%22MME%22%5D%0A%09%09%09%09%09PortAudioDirectSound%5Blabel%3D%22DirectSound%22%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20PortAudioWASAPI%5Blabel%3D%22WASAPI%22%5D%0A%09%09%09%09%09PortAudioWDMKS%5Blabel%3D%22WDM-KS%22%5D%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%7D%0A%09%7D%0A%0A%09subgraph%20clusterWindows%20%7B%0A%09%09label%3D%22Windows%20audio%20subsystem%22%0A%09%09subgraph%20%7B%0A%09%09%09rank%3D%22same%22%0A%09%09%09MME%0A%09%09%09DirectSound%0A%09%09%09%0A%09%09%7D%0A%09%09subgraph%20%7B%0A%09%09%09rank%3D%22same%22%0A%09%09%09WASAPIShared%5Blabel%3D%22WASAPI%20(shared)%22%5D%0A%09%09%09WASAPIExclusive%5Blabel%3D%22WASAPI%20(exclusive)%22%5D%0A%09%09%09WDMKS%5Blabel%3D%22Kernel%20Streaming%22%5D%0A%09%09%7D%0A%0A%09%09PreMix%5Blabel%3D%22Pre-mix%20APOs%22%5D%0A%09%09Mix%5Blabel%3D%22Mixing%22%5D%0A%09%09PostMix%5Blabel%3D%22Post-mix%20APOs%22%5D%0A%09%7D%0A%0A%09subgraph%20clusterHardware%20%7B%0A%09%09label%3D%22Audio%20hardware%22%0A%09%09HardwareDriver%5Blabel%3D%22Driver%22%5D%0A%09%09HardwareDevice%5Blabel%3D%22Device%22%5D%0A%09%7D%0A%0A%09Host-%3EFlexASIO%0A%09FlexASIO-%3EPortAudio%0A%0A%09PortAudio-%3E%7B%0A%09%09PortAudioMME%0A%09%09PortAudioDirectSound%0A%09%09PortAudioWASAPI%0A%09%09PortAudioWDMKS%0A%09%7D%0A%0A%09PortAudioMME-%3EMME%0A%09PortAudioDirectSound-%3EDirectSound%0A%09PortAudioWASAPI-%3EWASAPIShared%0A%09PortAudioWASAPI-%3EWASAPIExclusive%0A%09PortAudioWDMKS-%3EWDMKS%0A%0A%09MME-%3EWASAPIShared%0A%09DirectSound-%3EWASAPIShared%0A%09%0A%09WASAPIShared-%3EPreMix%0A%09WASAPIExclusive-%3EHardwareDriver%0A%09PreMix-%3EMix%0A%09Mix-%3EPostMix%0A%09PostMix-%3EHardwareDriver%0A%09%0A%09WDMKS-%3EHardwareDriver%0A%09%0A%09HardwareDriver-%3EHardwareDevice%0A%7D%0A
37 changes: 37 additions & 0 deletions CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,42 @@ wasapiExclusiveMode = true

The default behaviour is to open the stream in *shared* mode.

#### Option `wasapiAutoConvert`

*Boolean*-typed option that determines if WASAPI Shared is allowed to convert
the sample rate and channel count of the audio stream.

This option is ignored if the backend is not WASAPI. See the
[`backend` option][backend]. Furthermore, it is only effective when WASAPI is
used in *Shared mode*; WASAPI never converts *Exclusive mode* streams. See the
[`wasapiExclusiveMode` option][wasapiExclusiveMode].

If set to `true`, WASAPI will automatically convert the stream's sample rate
and channel count (upmixing/downmixing) if it doesn't match the *shared format*,
i.e. the format configured in the Windows audio control panel for that device.

If set to `false`, WASAPI will not do any sample rate and channel count
conversions and will only accept streams whose sample rate and channel count
match the one configured in the Windows audio control panel for that device. If
the sample rate or channel count don't match, FlexASIO will fail to initialize.
Note that WASAPI Shared might still do additional processing besides sample rate
and channel count conversion (e.g. sample format conversions, mixing, APOs).

Example:

```toml
backend = "Windows WASAPI"

[output]
wasapiAutoConvert = false
```

The default behaviour is to allow conversions.

(Note: as explained in [BACKENDS][], in modern versions of Windows, DirectSound
and MME use WASAPI Shared behind the scenes, and they implicitly enable the same
automatic conversion mechanism as the one this option controls.)

[backend]: #option-backend
[BACKENDS]: BACKENDS.md
[bufferSizeSamples]: #option-bufferSizeSamples
Expand All @@ -334,3 +370,4 @@ The default behaviour is to open the stream in *shared* mode.
[suggestedLatencySeconds]: #option-suggestedLatencySeconds
[TOML]: https://en.wikipedia.org/wiki/TOML
[WASAPI]: BACKENDS.md#wasapi-backend
[wasapiExclusiveMode]: #option-wasapiExclusiveMode
26 changes: 13 additions & 13 deletions FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,18 @@ settings. Here are some common issues:

- **Invalid values for configuration options** (e.g. wrong type, typos in
backend names or device names) will result in initialization failures.
- **When using WASAPI Shared…**
- **When using an exclusive backend (i.e. WASAPI Exclusive, WDM-KS)…**
- The **sample rate** selected in the ASIO Host Application must be natively
supported by the hardware audio device.
- The **channel count** that FlexASIO is configured to use must be natively
supported by the hardware audio device.
- **WDM-KS will fail to initialize if the selected device is already in use**
by any other application, even if no audio is actually playing. This means
that WDM-KS is unlikely to initialize successfully on the Windows default
devices; this can be worked around using the
[`device` configuration option][device].
- **When using WASAPI Shared with the [`wasapiAutoConvert` configuration
option][wasapiAutoConvert] disabled…**
- **Only one sample rate is supported**: the one configured in the Windows
audio device settings for the input *and* output devices.
- If the ASIO Host Application uses any other sample rate, FlexASIO will
Expand All @@ -52,17 +63,6 @@ settings. Here are some common issues:
audio device settings for the selected device.
- FlexASIO will fail to initialize if it is configured to use any other
channel count.
- These limitations are [inherent to WASAPI itself][wasapisr].
- **When using an exclusive backend (i.e. WASAPI Exclusive, WDM-KS)…**
- The **sample rate** selected in the ASIO Host Application must be natively
supported by the hardware audio device.
- The **channel count** that FlexASIO is configured to use must be natively
supported by the hardware audio device.
- **WDM-KS will fail to initialize if the selected device is already in use**
by any other application, even if no audio is actually playing. This means
that WDM-KS is unlikely to initialize successfully on the Windows default
devices; this can be worked around using the
[`device` configuration option][device].
- A **FlexASIO (or PortAudio) bug**. If you believe that is the case, please
[file a report][report].
- In particular, please do file a report if FlexASIO fails to initialize with
Expand Down Expand Up @@ -231,4 +231,4 @@ wasapiExclusiveMode = true
[report]: README.md#reporting-issues-feedback-feature-requests
[sampleType]: CONFIGURATION.md#option-sampleType
[suggestedLatencySeconds]: CONFIGURATION.md#option-suggestedLatencySeconds
[wasapisr]: https://docs.microsoft.com/windows/desktop/CoreAudio/device-formats
[wasapiAutoConvert]: CONFIGURATION.md#option-wasapiAutoConvert
1 change: 1 addition & 0 deletions src/flexasio/FlexASIO/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ namespace flexasio {
SetOption(table, "sampleType", stream.sampleType);
SetOption(table, "suggestedLatencySeconds", stream.suggestedLatencySeconds, ValidateSuggestedLatency);
SetOption(table, "wasapiExclusiveMode", stream.wasapiExclusiveMode);
SetOption(table, "wasapiAutoConvert", stream.wasapiAutoConvert);
}

void SetConfig(const toml::Table& table, Config& config) {
Expand Down
1 change: 1 addition & 0 deletions src/flexasio/FlexASIO/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ namespace flexasio {
std::optional<std::string> sampleType;
std::optional<double> suggestedLatencySeconds;
bool wasapiExclusiveMode = false;
bool wasapiAutoConvert = true;
};
Stream input;
Stream output;
Expand Down
8 changes: 8 additions & 0 deletions src/flexasio/FlexASIO/flexasio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,10 @@ namespace flexasio {
if (config.input.wasapiExclusiveMode) {
input_wasapi_stream_info.flags |= paWinWasapiExclusive;
}
Log() << (config.input.wasapiAutoConvert ? "Enabling" : "Disabling") << " auto-conversion for input WASAPI stream";
if (config.input.wasapiAutoConvert) {
input_wasapi_stream_info.flags |= paWinWasapiAutoConvert;
}
input_parameters.hostApiSpecificStreamInfo = &input_wasapi_stream_info;
}
}
Expand All @@ -545,6 +549,10 @@ namespace flexasio {
if (config.output.wasapiExclusiveMode) {
output_wasapi_stream_info.flags |= paWinWasapiExclusive;
}
Log() << (config.output.wasapiAutoConvert ? "Enabling" : "Disabling") << " auto-conversion for output WASAPI stream";
if (config.output.wasapiAutoConvert) {
output_wasapi_stream_info.flags |= paWinWasapiAutoConvert;
}
output_parameters.hostApiSpecificStreamInfo = &output_wasapi_stream_info;
}
}
Expand Down

0 comments on commit 00cfda7

Please sign in to comment.