improved PaWasapi_ThreadPriorityBoost by providing enum PaWasapiThreadPriority with explicit thread priority values for convenience. it is possible to override default thread priority setting for Event/Poll-driven modes by specifying new flag paWinWasapiThreadPriority and setting priority value through PaWasapiStreamInfo::threadPriority member.
This commit is contained in:
parent
8185016b2a
commit
75e59cb874
2 changed files with 101 additions and 38 deletions
|
|
@ -68,12 +68,17 @@ typedef enum PaWasapiFlags
|
||||||
Note: WASAPI Event driven core is capable of 2ms latency!!!, but Polling
|
Note: WASAPI Event driven core is capable of 2ms latency!!!, but Polling
|
||||||
method can only provide 15-20ms latency. */
|
method can only provide 15-20ms latency. */
|
||||||
paWinWasapiPolling = (1 << 3),
|
paWinWasapiPolling = (1 << 3),
|
||||||
|
|
||||||
|
/* forces custom thread priority setting. must be used if PaWasapiStreamInfo::threadPriority
|
||||||
|
is set to custom value. */
|
||||||
|
paWinWasapiThreadPriority = (1 << 4)
|
||||||
}
|
}
|
||||||
PaWasapiFlags;
|
PaWasapiFlags;
|
||||||
#define paWinWasapiExclusive (paWinWasapiExclusive)
|
#define paWinWasapiExclusive (paWinWasapiExclusive)
|
||||||
#define paWinWasapiRedirectHostProcessor (paWinWasapiRedirectHostProcessor)
|
#define paWinWasapiRedirectHostProcessor (paWinWasapiRedirectHostProcessor)
|
||||||
#define paWinWasapiUseChannelMask (paWinWasapiUseChannelMask)
|
#define paWinWasapiUseChannelMask (paWinWasapiUseChannelMask)
|
||||||
#define paWinWasapiPolling (paWinWasapiPolling)
|
#define paWinWasapiPolling (paWinWasapiPolling)
|
||||||
|
#define paWinWasapiThreadPriority (paWinWasapiThreadPriority)
|
||||||
|
|
||||||
|
|
||||||
/* Host processor. Allows to skip internal PA processing completely.
|
/* Host processor. Allows to skip internal PA processing completely.
|
||||||
|
|
@ -86,46 +91,6 @@ typedef void (*PaWasapiHostProcessorCallback) (void *inputBuffer, long inputFra
|
||||||
void *outputBuffer, long outputFrames,
|
void *outputBuffer, long outputFrames,
|
||||||
void *userData);
|
void *userData);
|
||||||
|
|
||||||
/* Stream descriptor. */
|
|
||||||
typedef struct PaWasapiStreamInfo
|
|
||||||
{
|
|
||||||
unsigned long size; /**< sizeof(PaWasapiStreamInfo) */
|
|
||||||
PaHostApiTypeId hostApiType; /**< paWASAPI */
|
|
||||||
unsigned long version; /**< 1 */
|
|
||||||
|
|
||||||
unsigned long flags; /**< collection of PaWasapiFlags */
|
|
||||||
|
|
||||||
/* Support for WAVEFORMATEXTENSIBLE channel masks. If flags contains
|
|
||||||
paWinWasapiUseChannelMask this allows you to specify which speakers
|
|
||||||
to address in a multichannel stream. Constants for channelMask
|
|
||||||
are specified in pa_win_waveformat.h
|
|
||||||
*/
|
|
||||||
PaWinWaveFormatChannelMask channelMask;
|
|
||||||
|
|
||||||
/* Delivers raw data to callback obtained from GetBuffer() methods skipping
|
|
||||||
internal PortAudio processing inventory completely. userData parameter will
|
|
||||||
be the same that was passed to Pa_OpenStream method.
|
|
||||||
*/
|
|
||||||
PaWasapiHostProcessorCallback hostProcessorOutput;
|
|
||||||
PaWasapiHostProcessorCallback hostProcessorInput;
|
|
||||||
}
|
|
||||||
PaWasapiStreamInfo;
|
|
||||||
|
|
||||||
|
|
||||||
/** Returns default sound format for device. Format is represented by PaWinWaveFormat or
|
|
||||||
WAVEFORMATEXTENSIBLE structure.
|
|
||||||
|
|
||||||
@param pFormat pointer to PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure.
|
|
||||||
@param nFormatSize pize of PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure in bytes.
|
|
||||||
@param nDevice device index.
|
|
||||||
|
|
||||||
@return A non-negative value indicating the number of bytes copied into format decriptor
|
|
||||||
or, a PaErrorCode (which are always negative) if PortAudio is not initialized
|
|
||||||
or an error is encountered.
|
|
||||||
*/
|
|
||||||
int PaWasapi_GetDeviceDefaultFormat( void *pFormat, int nFormatSize, PaDeviceIndex nDevice );
|
|
||||||
|
|
||||||
|
|
||||||
/* Device role */
|
/* Device role */
|
||||||
typedef enum PaWasapiDeviceRole
|
typedef enum PaWasapiDeviceRole
|
||||||
{
|
{
|
||||||
|
|
@ -144,6 +109,72 @@ typedef enum PaWasapiDeviceRole
|
||||||
PaWasapiDeviceRole;
|
PaWasapiDeviceRole;
|
||||||
|
|
||||||
|
|
||||||
|
/* Thread priority */
|
||||||
|
typedef enum PaWasapiThreadPriority
|
||||||
|
{
|
||||||
|
eThreadPriorityNone = 0,
|
||||||
|
eThreadPriorityAudio, //!< Default for Shared mode.
|
||||||
|
eThreadPriorityCapture,
|
||||||
|
eThreadPriorityDistribution,
|
||||||
|
eThreadPriorityGames,
|
||||||
|
eThreadPriorityPlayback,
|
||||||
|
eThreadPriorityProAudio, //!< Default for Exclusive mode.
|
||||||
|
eThreadPriorityWindowManager
|
||||||
|
}
|
||||||
|
PaWasapiThreadPriority;
|
||||||
|
|
||||||
|
|
||||||
|
/* Stream descriptor. */
|
||||||
|
typedef struct PaWasapiStreamInfo
|
||||||
|
{
|
||||||
|
unsigned long size; /**< sizeof(PaWasapiStreamInfo) */
|
||||||
|
PaHostApiTypeId hostApiType; /**< paWASAPI */
|
||||||
|
unsigned long version; /**< 1 */
|
||||||
|
|
||||||
|
unsigned long flags; /**< collection of PaWasapiFlags */
|
||||||
|
|
||||||
|
/* Support for WAVEFORMATEXTENSIBLE channel masks. If flags contains
|
||||||
|
paWinWasapiUseChannelMask this allows you to specify which speakers
|
||||||
|
to address in a multichannel stream. Constants for channelMask
|
||||||
|
are specified in pa_win_waveformat.h. Will be used only if
|
||||||
|
paWinWasapiUseChannelMask flag is specified.
|
||||||
|
*/
|
||||||
|
PaWinWaveFormatChannelMask channelMask;
|
||||||
|
|
||||||
|
/* Delivers raw data to callback obtained from GetBuffer() methods skipping
|
||||||
|
internal PortAudio processing inventory completely. userData parameter will
|
||||||
|
be the same that was passed to Pa_OpenStream method. Will be used only if
|
||||||
|
paWinWasapiRedirectHostProcessor flag is specified.
|
||||||
|
*/
|
||||||
|
PaWasapiHostProcessorCallback hostProcessorOutput;
|
||||||
|
PaWasapiHostProcessorCallback hostProcessorInput;
|
||||||
|
|
||||||
|
/* Specifies thread priority explicitly. Will be used only if paWinWasapiThreadPriority flag
|
||||||
|
is specified.
|
||||||
|
|
||||||
|
Please note, if Input/Output streams are opened simultaniously (Full-Duplex mode)
|
||||||
|
you shall specify same value for threadPriority or othervise one of the values will be used
|
||||||
|
to setup thread priority.
|
||||||
|
*/
|
||||||
|
PaWasapiThreadPriority threadPriority;
|
||||||
|
}
|
||||||
|
PaWasapiStreamInfo;
|
||||||
|
|
||||||
|
|
||||||
|
/** Returns default sound format for device. Format is represented by PaWinWaveFormat or
|
||||||
|
WAVEFORMATEXTENSIBLE structure.
|
||||||
|
|
||||||
|
@param pFormat pointer to PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure.
|
||||||
|
@param nFormatSize pize of PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure in bytes.
|
||||||
|
@param nDevice device index.
|
||||||
|
|
||||||
|
@return A non-negative value indicating the number of bytes copied into format decriptor
|
||||||
|
or, a PaErrorCode (which are always negative) if PortAudio is not initialized
|
||||||
|
or an error is encountered.
|
||||||
|
*/
|
||||||
|
int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int nFormatSize, PaDeviceIndex nDevice );
|
||||||
|
|
||||||
|
|
||||||
/** Returns device role (PaWasapiDeviceRole enum).
|
/** Returns device role (PaWasapiDeviceRole enum).
|
||||||
|
|
||||||
@param nDevice device index.
|
@param nDevice device index.
|
||||||
|
|
@ -160,18 +191,13 @@ int/*PaWasapiDeviceRole*/ PaWasapi_GetDeviceRole( PaDeviceIndex nDevice );
|
||||||
@param hTask a handle to pointer to priority task. Must be used with PaWasapi_RevertThreadPriority
|
@param hTask a handle to pointer to priority task. Must be used with PaWasapi_RevertThreadPriority
|
||||||
method to revert thread priority to initial state.
|
method to revert thread priority to initial state.
|
||||||
|
|
||||||
@param nPriorityClass an Id of thread priority: 1 - Audio
|
@param nPriorityClass an Id of thread priority of PaWasapiThreadPriority type. Specifying
|
||||||
2 - Capture
|
eThreadPriorityNone does nothing.
|
||||||
3 - Distribution
|
|
||||||
4 - Games
|
|
||||||
5 - Playback
|
|
||||||
6 - Pro Audio
|
|
||||||
7 - Window Manager
|
|
||||||
|
|
||||||
@return Error code indicating success or failure.
|
@return Error code indicating success or failure.
|
||||||
@see PaWasapi_RevertThreadPriority
|
@see PaWasapi_RevertThreadPriority
|
||||||
*/
|
*/
|
||||||
PaError PaWasapi_ThreadPriorityBoost( void **hTask, int nPriorityClass );
|
PaError PaWasapi_ThreadPriorityBoost( void **hTask, PaWasapiThreadPriority nPriorityClass );
|
||||||
|
|
||||||
|
|
||||||
/** Boost thread priority of calling thread (MMCSS). Use it for Blocking Interface only for thread
|
/** Boost thread priority of calling thread (MMCSS). Use it for Blocking Interface only for thread
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,8 @@ PA_THREAD_FUNC ProcThreadPoll(void *param);
|
||||||
|
|
||||||
enum { S_INPUT = 0, S_OUTPUT, S_COUNT };
|
enum { S_INPUT = 0, S_OUTPUT, S_COUNT };
|
||||||
|
|
||||||
|
#define STATIC_ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
|
||||||
|
|
||||||
#define PRINT(x) PA_DEBUG(x);
|
#define PRINT(x) PA_DEBUG(x);
|
||||||
|
|
||||||
#define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \
|
#define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \
|
||||||
|
|
@ -315,6 +317,9 @@ typedef struct PaWasapiStream
|
||||||
|
|
||||||
// Av Task (MM thread management)
|
// Av Task (MM thread management)
|
||||||
HANDLE hAvTask;
|
HANDLE hAvTask;
|
||||||
|
|
||||||
|
// Thread priority level
|
||||||
|
PaWasapiThreadPriority nThreadPriority;
|
||||||
}
|
}
|
||||||
PaWasapiStream;
|
PaWasapiStream;
|
||||||
|
|
||||||
|
|
@ -893,7 +898,7 @@ static inline PaWasapiHostApiRepresentation *GetHostApi(PaError *_error = NULL)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------
|
||||||
int PaWasapi_GetDeviceDefaultFormat( void *pFormat, int nFormatSize, PaDeviceIndex nDevice )
|
int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int nFormatSize, PaDeviceIndex nDevice )
|
||||||
{
|
{
|
||||||
if (pFormat == NULL)
|
if (pFormat == NULL)
|
||||||
return paBadBufferPtr;
|
return paBadBufferPtr;
|
||||||
|
|
@ -907,10 +912,10 @@ int PaWasapi_GetDeviceDefaultFormat( void *pFormat, int nFormatSize, PaDeviceInd
|
||||||
if (paWasapi == NULL)
|
if (paWasapi == NULL)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (nDevice >= (int)paWasapi->deviceCount)
|
if ((UINT32)nDevice >= paWasapi->deviceCount)
|
||||||
return paInvalidDevice;
|
return paInvalidDevice;
|
||||||
|
|
||||||
int size = min(nFormatSize, sizeof(paWasapi->devInfo[ nDevice ].DefaultFormat));
|
UINT32 size = min(nFormatSize, (UINT32)sizeof(paWasapi->devInfo[ nDevice ].DefaultFormat));
|
||||||
memcpy(pFormat, &paWasapi->devInfo[ nDevice ].DefaultFormat, size);
|
memcpy(pFormat, &paWasapi->devInfo[ nDevice ].DefaultFormat, size);
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
|
|
@ -1560,6 +1565,9 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default thread priority is Audio: for exclusive mode we will use Pro Audio.
|
||||||
|
stream->nThreadPriority = eThreadPriorityAudio;
|
||||||
|
|
||||||
// Try create device: Input
|
// Try create device: Input
|
||||||
if (inputParameters != NULL)
|
if (inputParameters != NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -1572,7 +1580,20 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
// Select Exclusive/Shared mode
|
// Select Exclusive/Shared mode
|
||||||
stream->in.shareMode = AUDCLNT_SHAREMODE_SHARED;
|
stream->in.shareMode = AUDCLNT_SHAREMODE_SHARED;
|
||||||
if ((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiExclusive))
|
if ((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiExclusive))
|
||||||
|
{
|
||||||
|
// Boost thread priority
|
||||||
|
stream->nThreadPriority = eThreadPriorityProAudio;
|
||||||
|
// Make Exclusive
|
||||||
stream->in.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;
|
stream->in.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If user provided explicit thread priority level, use it
|
||||||
|
if ((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiThreadPriority))
|
||||||
|
{
|
||||||
|
if ((inputStreamInfo->threadPriority > eThreadPriorityNone) &&
|
||||||
|
(inputStreamInfo->threadPriority <= eThreadPriorityWindowManager))
|
||||||
|
stream->nThreadPriority = inputStreamInfo->threadPriority;
|
||||||
|
}
|
||||||
|
|
||||||
// Choose processing mode
|
// Choose processing mode
|
||||||
stream->in.streamFlags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
|
stream->in.streamFlags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
|
||||||
|
|
@ -1661,7 +1682,20 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
// Select Exclusive/Shared mode
|
// Select Exclusive/Shared mode
|
||||||
stream->out.shareMode = AUDCLNT_SHAREMODE_SHARED;
|
stream->out.shareMode = AUDCLNT_SHAREMODE_SHARED;
|
||||||
if ((outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiExclusive))
|
if ((outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiExclusive))
|
||||||
|
{
|
||||||
|
// Boost thread priority
|
||||||
|
stream->nThreadPriority = eThreadPriorityProAudio;
|
||||||
|
// Make Exclusive
|
||||||
stream->out.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;
|
stream->out.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If user provided explicit thread priority level, use it
|
||||||
|
if ((outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiThreadPriority))
|
||||||
|
{
|
||||||
|
if ((outputStreamInfo->threadPriority > eThreadPriorityNone) &&
|
||||||
|
(outputStreamInfo->threadPriority <= eThreadPriorityWindowManager))
|
||||||
|
stream->nThreadPriority = outputStreamInfo->threadPriority;
|
||||||
|
}
|
||||||
|
|
||||||
// Choose processing mode
|
// Choose processing mode
|
||||||
stream->out.streamFlags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
|
stream->out.streamFlags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
|
||||||
|
|
@ -2440,13 +2474,14 @@ void MMCSS_deactivate(HANDLE hTask)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------
|
||||||
PaError PaWasapi_ThreadPriorityBoost(void **hTask, int nPriorityClass)
|
PaError PaWasapi_ThreadPriorityBoost(void **hTask, PaWasapiThreadPriority nPriorityClass)
|
||||||
{
|
{
|
||||||
if (hTask == NULL)
|
if (hTask == NULL)
|
||||||
return paUnanticipatedHostError;
|
return paUnanticipatedHostError;
|
||||||
|
|
||||||
static const char *mmcs_name[7] =
|
static const char *mmcs_name[] =
|
||||||
{
|
{
|
||||||
|
NULL,
|
||||||
"Audio",
|
"Audio",
|
||||||
"Capture",
|
"Capture",
|
||||||
"Distribution",
|
"Distribution",
|
||||||
|
|
@ -2455,7 +2490,7 @@ PaError PaWasapi_ThreadPriorityBoost(void **hTask, int nPriorityClass)
|
||||||
"Pro Audio",
|
"Pro Audio",
|
||||||
"Window Manager"
|
"Window Manager"
|
||||||
};
|
};
|
||||||
if ((UINT32)nPriorityClass >= 7)
|
if ((UINT32)nPriorityClass >= STATIC_ARRAY_SIZE(mmcs_name))
|
||||||
return paUnanticipatedHostError;
|
return paUnanticipatedHostError;
|
||||||
|
|
||||||
HANDLE task = MMCSS_activate(mmcs_name[nPriorityClass]);
|
HANDLE task = MMCSS_activate(mmcs_name[nPriorityClass]);
|
||||||
|
|
@ -2546,7 +2581,7 @@ void _OnStreamStop(PaWasapiStream *stream)
|
||||||
// Restore thread priority
|
// Restore thread priority
|
||||||
if (stream->hAvTask != NULL)
|
if (stream->hAvTask != NULL)
|
||||||
{
|
{
|
||||||
MMCSS_deactivate(stream->hAvTask);
|
PaWasapi_ThreadPriorityRevert(stream->hAvTask);
|
||||||
stream->hAvTask = NULL;
|
stream->hAvTask = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2584,7 +2619,8 @@ PA_THREAD_FUNC ProcThreadEvent(void *param)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Boost thread priority
|
// Boost thread priority
|
||||||
stream->hAvTask = MMCSS_activate("Pro Audio");
|
stream->hAvTask = NULL;
|
||||||
|
PaWasapi_ThreadPriorityBoost((void **)&stream->hAvTask, stream->nThreadPriority);
|
||||||
|
|
||||||
// Initialize event & start INPUT stream
|
// Initialize event & start INPUT stream
|
||||||
if (stream->in.client)
|
if (stream->in.client)
|
||||||
|
|
@ -2693,7 +2729,8 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
|
||||||
processor[S_OUTPUT] = (stream->hostProcessOverrideOutput.processor != NULL ? stream->hostProcessOverrideOutput : defaultProcessor);
|
processor[S_OUTPUT] = (stream->hostProcessOverrideOutput.processor != NULL ? stream->hostProcessOverrideOutput : defaultProcessor);
|
||||||
|
|
||||||
// Boost thread priority
|
// Boost thread priority
|
||||||
stream->hAvTask = MMCSS_activate("Pro Audio");
|
stream->hAvTask = NULL;
|
||||||
|
PaWasapi_ThreadPriorityBoost((void **)&stream->hAvTask, stream->nThreadPriority);
|
||||||
|
|
||||||
// Initialize event & start INPUT stream
|
// Initialize event & start INPUT stream
|
||||||
if (stream->in.client)
|
if (stream->in.client)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue