wasapi: Add paWinWasapiAutoConvert flag, which sets AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY for Shared mode streams.

AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM is required in order to allow for sample rates other than the system mixer configured sample rate. Otherwise, WASAPI is limited to a single system configured sample rate in Shared mode, which is a severe limitation compared to other APIs supported by PortAudio.
AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY is recommended to be used additionally.
See <https://docs.microsoft.com/en-us/windows/desktop/coreaudio/audclnt-streamflags-xxx-constants> for documentation.

GetClosestFormat is modified to exit early when paWinWasapiAutoConvert is set in Shared mode because we trust the WASAPI conversions to succeed.

We restrict these changes to Windows 7 (and later) because documentation does not clearly state the minimum required Windows version. Windows Vista was not available for testing.

This patch has been in production in OpenMPT (<https://openmpt.org/>) since version 1.27.01.00 (2017-09-27). PortAudio WASAPI Shared mode is the default output device type in OpenMPT for Windows 7 (and later) and also for Wine setups.
This commit is contained in:
Jörn Heusipp 2019-04-01 09:05:18 +02:00 committed by dmitrykos
commit aa0748a5b5
2 changed files with 25 additions and 1 deletions

View file

@ -293,6 +293,13 @@ PA_THREAD_FUNC ProcThreadPoll(void *param);
#define AUDCLNT_E_INVALID_DEVICE_PERIOD AUDCLNT_ERR(0x020)
#endif
#ifndef AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
#define AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY 0x08000000
#endif
#ifndef AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
#define AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000
#endif
#define MAX_STR_LEN 512
#ifdef PA_WINRT
@ -2667,6 +2674,10 @@ static PaError GetClosestFormat(IAudioClient *client, double sampleRate, const P
// Try standard approach, e.g. if data is > 16 bits it will be packed into 32-bit containers
MakeWaveFormatFromParams(outWavex, &params, sampleRate, FALSE);
if ((GetWindowsVersion() >= WINDOWS_7_SERVER2008R2) && (shareMode == AUDCLNT_SHAREMODE_SHARED) && _params->hostApiSpecificStreamInfo && (((PaWasapiStreamInfo *)_params->hostApiSpecificStreamInfo)->flags & paWinWasapiAutoConvert))
{
return paFormatIsSupported;
}
hr = IAudioClient_IsFormatSupported(client, shareMode, &outWavex->Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));
// Exclusive mode can require packed format for some devices
@ -3586,6 +3597,9 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
if (fullDuplex)
stream->in.streamFlags = 0; // polling interface is implemented for full-duplex mode also
if ((GetWindowsVersion() >= WINDOWS_7_SERVER2008R2) && (stream->in.shareMode == AUDCLNT_SHAREMODE_SHARED) && (inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiAutoConvert))
stream->in.streamFlags |= AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
// Fill parameters for Audio Client creation
stream->in.params.device_info = info;
stream->in.params.stream_params = (*inputParameters);
@ -3714,6 +3728,9 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
if (fullDuplex)
stream->out.streamFlags = 0; // polling interface is implemented for full-duplex mode also
if ((GetWindowsVersion() >= WINDOWS_7_SERVER2008R2) && (stream->out.shareMode == AUDCLNT_SHAREMODE_SHARED) && (outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiAutoConvert))
stream->out.streamFlags |= AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
// Fill parameters for Audio Client creation
stream->out.params.device_info = info;
stream->out.params.stream_params = (*outputParameters);