]> Repos - portaudio/commitdiff
wasapi: Add paWinWasapiAutoConvert flag, which sets AUDCLNT_STREAMFLAGS_AUTOCONVERTPC...
authorJörn Heusipp <osmanx@problemloesungsmaschine.de>
Mon, 1 Apr 2019 07:05:18 +0000 (09:05 +0200)
committerdmitrykos <dmitrykos@neutroncode.com>
Fri, 5 Apr 2019 07:02:17 +0000 (10:02 +0300)
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.

include/pa_win_wasapi.h
src/hostapi/wasapi/pa_win_wasapi.c

index 63b5d6a7c4549191a7577555e5f8be82d9f7e9fc..9b827d1ea25f443541d609a9b883ba1f72e7af2c 100644 (file)
@@ -78,7 +78,13 @@ typedef enum PaWasapiFlags
     /* force explicit sample format and do not allow PA to select suitable working format, API will
        fail if provided sample format is not supported by audio hardware in Exclusive mode
        or system mixer in Shared mode */
-    paWinWasapiExplicitSampleFormat     = (1 << 5)
+    paWinWasapiExplicitSampleFormat     = (1 << 5),
+
+    /* allow API to insert system-level channel matrix mixer and sample rate converter to allow
+       playback formats that do not match the current configured system settings.
+       this is in particular required for streams not matching the system mixer sample rate.
+       only applies in Shared mode. */
+    paWinWasapiAutoConvert              = (1 << 6)
 }
 PaWasapiFlags;
 #define paWinWasapiExclusive             (paWinWasapiExclusive)
@@ -87,6 +93,7 @@ PaWasapiFlags;
 #define paWinWasapiPolling               (paWinWasapiPolling)
 #define paWinWasapiThreadPriority        (paWinWasapiThreadPriority)
 #define paWinWasapiExplicitSampleFormat  (paWinWasapiExplicitSampleFormat)
+#define paWinWasapiAutoConvert           (paWinWasapiAutoConvert)
 
 
 /* Stream state.
index ffc4b11d006bad51b81d82855567adb69d7ea4f0..c55c8b55899647202b467cfb06b9506eb7168fb5 100644 (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);