@@ -326,7 +326,7 @@ typedef struct PaWinDsStream
326
326
/* Set minimal latency based on the current OS version.
327
327
* NT has higher latency.
328
328
*/
329
- static double PaWinDS_GetMinSystemLatencySeconds ( void )
329
+ static DWORD PaWinDS_GetWindowsMajorVersion ( void )
330
330
{
331
331
/*
332
332
NOTE: GetVersionEx() is deprecated as of Windows 8.1 and can not be used to reliably detect
@@ -338,23 +338,33 @@ See: http://www.codeproject.com/Articles/678606/Part-Overcoming-Windows-s-deprec
338
338
*/
339
339
#pragma warning (disable : 4996) /* use of GetVersionEx */
340
340
341
+ OSVERSIONINFO osvi ;
342
+ osvi .dwOSVersionInfoSize = sizeof (osvi );
343
+ GetVersionEx (& osvi );
344
+ return osvi .dwMajorVersion ;
345
+
346
+ #pragma warning (default : 4996)
347
+ }
348
+
349
+
350
+ /* Set minimal latency based on the current OS version.
351
+ * NT has higher latency.
352
+ */
353
+ static double PaWinDS_GetMinSystemLatencySeconds ( void )
354
+ {
341
355
double minLatencySeconds ;
342
356
/* Set minimal latency based on whether NT or other OS.
343
357
* NT has higher latency.
344
358
*/
345
359
346
- OSVERSIONINFO osvi ;
347
- osvi .dwOSVersionInfoSize = sizeof ( osvi );
348
- GetVersionEx ( & osvi );
349
- DBUG (("PA - PlatformId = 0x%x\n" , osvi .dwPlatformId ));
350
- DBUG (("PA - MajorVersion = 0x%x\n" , osvi .dwMajorVersion ));
351
- DBUG (("PA - MinorVersion = 0x%x\n" , osvi .dwMinorVersion ));
360
+ const DWORD windowsMajorVersion = PaWinDS_GetWindowsMajorVersion ();
361
+ DBUG (("PA - windowsMajorVersion = 0x%x\n" , windowsMajorVersion ));
352
362
/* Check for NT */
353
- if ( (osvi . dwMajorVersion == 4 ) && (osvi . dwPlatformId == 2 ) )
363
+ if ( (windowsMajorVersion == 4 ) && (windowsMajorVersion == 2 ) )
354
364
{
355
365
minLatencySeconds = PA_DS_WIN_NT_DEFAULT_LATENCY_ ;
356
366
}
357
- else if (osvi . dwMajorVersion >= 5 )
367
+ else if (windowsMajorVersion >= 5 )
358
368
{
359
369
minLatencySeconds = PA_DS_WIN_WDM_DEFAULT_LATENCY_ ;
360
370
}
@@ -363,8 +373,6 @@ See: http://www.codeproject.com/Articles/678606/Part-Overcoming-Windows-s-deprec
363
373
minLatencySeconds = PA_DS_WIN_9X_DEFAULT_LATENCY_ ;
364
374
}
365
375
return minLatencySeconds ;
366
-
367
- #pragma warning (default : 4996)
368
376
}
369
377
370
378
@@ -1741,7 +1749,7 @@ static HRESULT InitOutputBuffer( PaWinDsStream *stream, PaWinDsDeviceInfo *devic
1741
1749
1742
1750
static void CalculateBufferSettings ( unsigned long * hostBufferSizeFrames ,
1743
1751
unsigned long * pollingPeriodFrames ,
1744
- int isFullDuplex ,
1752
+ int hasInput , int hasOutput ,
1745
1753
unsigned long suggestedInputLatencyFrames ,
1746
1754
unsigned long suggestedOutputLatencyFrames ,
1747
1755
double sampleRate , unsigned long userFramesPerBuffer )
@@ -1751,7 +1759,7 @@ static void CalculateBufferSettings( unsigned long *hostBufferSizeFrames,
1751
1759
unsigned long pollingJitterFrames = (unsigned long )(sampleRate * PA_DS_POLLING_JITTER_SECONDS );
1752
1760
1753
1761
unsigned long adjustedSuggestedOutputLatencyFrames = suggestedOutputLatencyFrames ;
1754
- if ( userFramesPerBuffer != paFramesPerBufferUnspecified && isFullDuplex )
1762
+ if ( userFramesPerBuffer != paFramesPerBufferUnspecified && hasInput && hasOutput )
1755
1763
{
1756
1764
/* In full duplex streams we know that the buffer adapter adds userFramesPerBuffer
1757
1765
extra fixed latency. so we subtract it here as a fixed latency before computing
@@ -1773,6 +1781,21 @@ static void CalculateBufferSettings( unsigned long *hostBufferSizeFrames,
1773
1781
userFramesPerBuffer ;
1774
1782
* hostBufferSizeFrames = intendedUserFramesPerBuffer
1775
1783
+ max ( intendedUserFramesPerBuffer + pollingJitterFrames , targetBufferingLatencyFrames );
1784
+
1785
+ /* In some (most?) systems, DirectSound has an odd limitation where it always uses
1786
+ a fixed 31.25 ms granularity for the read cursor, regardless of parameters.
1787
+ This in turn means that if we allocate an input buffer that is less than 31.25 ms,
1788
+ the read cursor will stay stuck at zero. See https://github.com/PortAudio/portaudio/issues/775
1789
+ To work around this problem, ensure that the input host buffer is large enough
1790
+ for at least two 31.25 ms buffer "halves".
1791
+
1792
+ On pre-Vista Windows, we don't do this because DirectSound is implemented very
1793
+ differently, and is therefore unlikely to suffer from the same issue.
1794
+ */
1795
+ if ( hasInput && PaWinDS_GetWindowsMajorVersion () >= 6 )
1796
+ {
1797
+ * hostBufferSizeFrames = max ( * hostBufferSizeFrames , 2 * 0.03125 * sampleRate );
1798
+ }
1776
1799
}
1777
1800
1778
1801
@@ -2108,7 +2131,8 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
2108
2131
else
2109
2132
{
2110
2133
CalculateBufferSettings ( (unsigned long * )& stream -> hostBufferSizeFrames , & pollingPeriodFrames ,
2111
- /* isFullDuplex = */ (inputParameters && outputParameters ),
2134
+ /* hasInput = */ !!inputParameters ,
2135
+ /* hasOutput = */ !!outputParameters ,
2112
2136
suggestedInputLatencyFrames ,
2113
2137
suggestedOutputLatencyFrames ,
2114
2138
sampleRate , framesPerBuffer );
0 commit comments