Browse Source

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.
winrt
Jörn Heusipp 3 months ago
parent
commit
aa0748a5b5
2 changed files with 25 additions and 1 deletions
  1. 8
    1
      include/pa_win_wasapi.h
  2. 17
    0
      src/hostapi/wasapi/pa_win_wasapi.c

+ 8
- 1
include/pa_win_wasapi.h View File

@@ -78,7 +78,13 @@ typedef enum PaWasapiFlags
78 78
     /* force explicit sample format and do not allow PA to select suitable working format, API will
79 79
        fail if provided sample format is not supported by audio hardware in Exclusive mode
80 80
        or system mixer in Shared mode */
81
-    paWinWasapiExplicitSampleFormat     = (1 << 5)
81
+    paWinWasapiExplicitSampleFormat     = (1 << 5),
82
+
83
+    /* allow API to insert system-level channel matrix mixer and sample rate converter to allow
84
+       playback formats that do not match the current configured system settings.
85
+       this is in particular required for streams not matching the system mixer sample rate.
86
+       only applies in Shared mode. */
87
+    paWinWasapiAutoConvert              = (1 << 6)
82 88
 }
83 89
 PaWasapiFlags;
84 90
 #define paWinWasapiExclusive             (paWinWasapiExclusive)
@@ -87,6 +93,7 @@ PaWasapiFlags;
87 93
 #define paWinWasapiPolling               (paWinWasapiPolling)
88 94
 #define paWinWasapiThreadPriority        (paWinWasapiThreadPriority)
89 95
 #define paWinWasapiExplicitSampleFormat  (paWinWasapiExplicitSampleFormat)
96
+#define paWinWasapiAutoConvert           (paWinWasapiAutoConvert)
90 97
 
91 98
 
92 99
 /* Stream state.

+ 17
- 0
src/hostapi/wasapi/pa_win_wasapi.c View File

@@ -293,6 +293,13 @@ PA_THREAD_FUNC ProcThreadPoll(void *param);
293 293
 	#define AUDCLNT_E_INVALID_DEVICE_PERIOD AUDCLNT_ERR(0x020)
294 294
 #endif
295 295
 
296
+#ifndef AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY
297
+	#define AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY 0x08000000
298
+#endif
299
+#ifndef AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
300
+	#define AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM 0x80000000
301
+#endif
302
+
296 303
 #define MAX_STR_LEN 512
297 304
 
298 305
 #ifdef PA_WINRT
@@ -2667,6 +2674,10 @@ static PaError GetClosestFormat(IAudioClient *client, double sampleRate, const P
2667 2674
 
2668 2675
 	// Try standard approach, e.g. if data is > 16 bits it will be packed into 32-bit containers
2669 2676
     MakeWaveFormatFromParams(outWavex, &params, sampleRate, FALSE);
2677
+	if ((GetWindowsVersion() >= WINDOWS_7_SERVER2008R2) && (shareMode == AUDCLNT_SHAREMODE_SHARED) && _params->hostApiSpecificStreamInfo && (((PaWasapiStreamInfo *)_params->hostApiSpecificStreamInfo)->flags & paWinWasapiAutoConvert))
2678
+	{
2679
+		return paFormatIsSupported;
2680
+	}
2670 2681
 	hr = IAudioClient_IsFormatSupported(client, shareMode, &outWavex->Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));
2671 2682
 	
2672 2683
 	// Exclusive mode can require packed format for some devices
@@ -3586,6 +3597,9 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
3586 3597
 		if (fullDuplex)
3587 3598
 			stream->in.streamFlags = 0; // polling interface is implemented for full-duplex mode also
3588 3599
 
3600
+		if ((GetWindowsVersion() >= WINDOWS_7_SERVER2008R2) && (stream->in.shareMode == AUDCLNT_SHAREMODE_SHARED) && (inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiAutoConvert))
3601
+			stream->in.streamFlags |= AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
3602
+
3589 3603
 		// Fill parameters for Audio Client creation
3590 3604
 		stream->in.params.device_info       = info;
3591 3605
 		stream->in.params.stream_params     = (*inputParameters);
@@ -3714,6 +3728,9 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
3714 3728
 		if (fullDuplex)
3715 3729
 			stream->out.streamFlags = 0; // polling interface is implemented for full-duplex mode also
3716 3730
 
3731
+		if ((GetWindowsVersion() >= WINDOWS_7_SERVER2008R2) && (stream->out.shareMode == AUDCLNT_SHAREMODE_SHARED) && (outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiAutoConvert))
3732
+			stream->out.streamFlags |= AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
3733
+
3717 3734
 		// Fill parameters for Audio Client creation
3718 3735
 		stream->out.params.device_info       = info;
3719 3736
 		stream->out.params.stream_params     = (*outputParameters);

Loading…
Cancel
Save