Browse Source

Merge branch 'winrt' into 'master'

WASAPI: fix rare case when Shared Mode format obtained by PKEY_AudioEngine_DeviceFormat not accepted by WASAPI

Merged-on: https://assembla.com/code/portaudio/git/merge_requests/7085071
mr/new/b22a83a6006237071d7439e0f196e55d6f3e6651
Dmitry Kostjuchenko 10 months ago
parent
commit
b22a83a600
2 changed files with 73 additions and 13 deletions
  1. 19
    3
      include/pa_win_wasapi.h
  2. 54
    10
      src/hostapi/wasapi/pa_win_wasapi.c

+ 19
- 3
include/pa_win_wasapi.h View File

@@ -320,7 +320,7 @@ PaError PaWasapi_GetAudioClient( PaStream *pStream, void **pAudioClient, int bOu
PaError PaWasapi_UpdateDeviceList();


/** Returns current sound format of the device assigned to the opened stream. Format is represented by
/** Returns current audio format of the device assigned to the opened stream. Format is represented by
PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure. Use this function to reconfirm format if
PA's processor is overriden and paWinWasapiRedirectHostProcessor flag is specified.

@@ -336,8 +336,9 @@ PaError PaWasapi_UpdateDeviceList();
int PaWasapi_GetDeviceCurrentFormat( PaStream *pStream, void *pFormat, unsigned int nFormatSize, int bOutput );


/** Returns default sound format for device. Format is represented by PaWinWaveFormat or
WAVEFORMATEXTENSIBLE structure.
/** Returns default audio format for device in Shared Mode. Format is represented by
PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure and obtained by getting
the device property with a PKEY_AudioEngine_DeviceFormat key.

@param pFormat Pointer to PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure.
@param nFormatSize Size of PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure in bytes.
@@ -350,6 +351,21 @@ int PaWasapi_GetDeviceCurrentFormat( PaStream *pStream, void *pFormat, unsigned
int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int nFormatSize, PaDeviceIndex nDevice );


/** Returns mix audio format for device in Shared Mode. Format is represented by
PaWinWaveFormat or WAVEFORMATEXTENSIBLE structureand obtained by
IAudioClient::GetMixFormat.

@param pFormat Pointer to PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure.
@param nFormatSize Size of PaWinWaveFormat or WAVEFORMATEXTENSIBLE structure in bytes.
@param nDevice Device index.

@return 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_GetDeviceMixFormat( void *pFormat, unsigned int nFormatSize, PaDeviceIndex nDevice );


/** Returns device role (PaWasapiDeviceRole enum).

@param nDevice Device index.

+ 54
- 10
src/hostapi/wasapi/pa_win_wasapi.c View File

@@ -427,6 +427,9 @@ typedef struct PaWasapiDeviceInfo
// Default format (setup through Control Panel by user)
WAVEFORMATEXTENSIBLE DefaultFormat;

// Mix format (internal format used by WASAPI audio engine)
WAVEFORMATEXTENSIBLE MixFormat;

// Fields filled from IMMEndpoint'sGetDataFlow
EDataFlow flow;

@@ -1591,8 +1594,6 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
#ifndef PA_WINRT
IMMDeviceCollection* pEndPoints = NULL;
IMMDeviceEnumerator *pEnumerator = NULL;
#else
WAVEFORMATEX *mixFormat;
#endif
IAudioClient *tmpClient;

@@ -1871,9 +1872,20 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
hr = S_OK;
}
// Get mix format
{
WAVEFORMATEX *mixFormat;

hr = IAudioClient_GetMixFormat(tmpClient, &mixFormat);
if (SUCCEEDED(hr))
{
memcpy(&paWasapi->devInfo[i].MixFormat, mixFormat, min(sizeof(paWasapi->devInfo[i].MixFormat), (sizeof(*mixFormat) + mixFormat->cbSize)));
CoTaskMemFree(mixFormat);
}
}

// Register WINRT device
#ifdef PA_WINRT
// Get mix format which will treat as default device format
hr = IAudioClient_GetMixFormat(tmpClient, &mixFormat);
if (SUCCEEDED(hr))
{
// Default device
@@ -1885,9 +1897,8 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
// State
paWasapi->devInfo[i].state = DEVICE_STATE_ACTIVE;

// Default format
memcpy(&paWasapi->devInfo[i].DefaultFormat, mixFormat, min(sizeof(paWasapi->devInfo[i].DefaultFormat), (sizeof(*mixFormat) + mixFormat->cbSize)));
CoTaskMemFree(mixFormat);
// Default format is always a mix format
paWasapi->devInfo[i].DefaultFormat = paWasapi->devInfo[i].MixFormat;

// Form-factor
paWasapi->devInfo[i].formFactor = UnknownFormFactor;
@@ -1922,18 +1933,18 @@ static PaError CreateDeviceList(PaWasapiHostApiRepresentation *paWasapi, PaHostA
// we can now fill in portaudio device data
deviceInfo->maxInputChannels = 0;
deviceInfo->maxOutputChannels = 0;
deviceInfo->defaultSampleRate = paWasapi->devInfo[i].DefaultFormat.Format.nSamplesPerSec;
deviceInfo->defaultSampleRate = paWasapi->devInfo[i].MixFormat.Format.nSamplesPerSec;
switch (paWasapi->devInfo[i].flow)
{
case eRender: {
deviceInfo->maxOutputChannels = paWasapi->devInfo[i].DefaultFormat.Format.nChannels;
deviceInfo->maxOutputChannels = paWasapi->devInfo[i].MixFormat.Format.nChannels;
deviceInfo->defaultHighOutputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod);
deviceInfo->defaultLowOutputLatency = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod);
PA_DEBUG(("WASAPI:%d| def.SR[%d] max.CH[%d] latency{hi[%f] lo[%f]}\n", i, (UINT32)deviceInfo->defaultSampleRate,
deviceInfo->maxOutputChannels, (float)deviceInfo->defaultHighOutputLatency, (float)deviceInfo->defaultLowOutputLatency));
break;}
case eCapture: {
deviceInfo->maxInputChannels = paWasapi->devInfo[i].DefaultFormat.Format.nChannels;
deviceInfo->maxInputChannels = paWasapi->devInfo[i].MixFormat.Format.nChannels;
deviceInfo->defaultHighInputLatency = nano100ToSeconds(paWasapi->devInfo[i].DefaultDevicePeriod);
deviceInfo->defaultLowInputLatency = nano100ToSeconds(paWasapi->devInfo[i].MinimumDevicePeriod);
PA_DEBUG(("WASAPI:%d| def.SR[%d] max.CH[%d] latency{hi[%f] lo[%f]}\n", i, (UINT32)deviceInfo->defaultSampleRate,
@@ -2229,6 +2240,39 @@ int PaWasapi_GetDeviceDefaultFormat( void *pFormat, unsigned int nFormatSize, Pa
}

// ------------------------------------------------------------------------------------------
int PaWasapi_GetDeviceMixFormat( void *pFormat, unsigned int nFormatSize, PaDeviceIndex nDevice )
{
PaError ret;
PaWasapiHostApiRepresentation *paWasapi;
UINT32 size;
PaDeviceIndex index;

if (pFormat == NULL)
return paBadBufferPtr;
if (nFormatSize <= 0)
return paBufferTooSmall;

// Get API
paWasapi = _GetHostApi(&ret);
if (paWasapi == NULL)
return ret;

// Get device index
ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, nDevice, &paWasapi->inheritedHostApiRep);
if (ret != paNoError)
return ret;

// Validate index
if ((UINT32)index >= paWasapi->deviceCount)
return paInvalidDevice;
size = min(nFormatSize, (UINT32)sizeof(paWasapi->devInfo[ index ].MixFormat));
memcpy(pFormat, &paWasapi->devInfo[ index ].MixFormat, size);

return size;
}

// ------------------------------------------------------------------------------------------
int PaWasapi_GetDeviceRole( PaDeviceIndex nDevice )
{
PaError ret;

Loading…
Cancel
Save