static void _OnStreamStop(PaWasapiStream *stream);\r
static void _FinishStream(PaWasapiStream *stream);\r
\r
+// Local statics\r
+static volatile BOOL g_bCOMInitialized = FALSE;\r
+\r
// ------------------------------------------------------------------------------------------\r
#define LogHostError(HRES) __LogHostError(HRES, __FUNCTION__, __FILE__, __LINE__)\r
static HRESULT __LogHostError(HRESULT res, const char *func, const char *file, int line)\r
PaError result = paNoError;\r
PaWasapiHostApiRepresentation *paWasapi;\r
PaDeviceInfo *deviceInfoArray;\r
- HRESULT hResult = S_OK;\r
+ HRESULT hr = S_OK;\r
IMMDeviceCollection* pEndPoints = NULL;\r
UINT i;\r
\r
return paNoError;\r
}\r
\r
- CoInitialize(NULL);\r
+ /*\r
+ If COM is already initialized CoInitialize will either return\r
+ FALSE, or RPC_E_CHANGED_MODE if it was initialised in a different\r
+ threading mode. In either case we shouldn't consider it an error\r
+ but we need to be careful to not call CoUninitialize() if \r
+ RPC_E_CHANGED_MODE was returned.\r
+ */\r
+ hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);\r
+ if (FAILED(hr) && (hr != RPC_E_CHANGED_MODE))\r
+ {\r
+ PRINT(("WASAPI: failed CoInitialize"));\r
+ return paUnanticipatedHostError;\r
+ }\r
+ if (hr != RPC_E_CHANGED_MODE)\r
+ g_bCOMInitialized = TRUE;\r
\r
paWasapi = (PaWasapiHostApiRepresentation *)PaUtil_AllocateMemory( sizeof(PaWasapiHostApiRepresentation) );\r
if (paWasapi == NULL)\r
(*hostApi)->info.defaultOutputDevice = paNoDevice;\r
\r
paWasapi->enumerator = NULL;\r
- hResult = CoCreateInstance(&pa_CLSID_IMMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER,\r
+ hr = CoCreateInstance(&pa_CLSID_IMMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER,\r
&pa_IID_IMMDeviceEnumerator, (void **)&paWasapi->enumerator);\r
- IF_FAILED_JUMP(hResult, error);\r
+ IF_FAILED_JUMP(hr, error);\r
\r
// getting default device ids in the eMultimedia "role"\r
{\r
{\r
IMMDevice *defaultRenderer = NULL;\r
- hResult = IMMDeviceEnumerator_GetDefaultAudioEndpoint(paWasapi->enumerator, eRender, eMultimedia, &defaultRenderer);\r
- if (hResult != S_OK)\r
+ hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(paWasapi->enumerator, eRender, eMultimedia, &defaultRenderer);\r
+ if (hr != S_OK)\r
{\r
- if (hResult != E_NOTFOUND)\r
- IF_FAILED_JUMP(hResult, error);\r
+ if (hr != E_NOTFOUND)\r
+ IF_FAILED_JUMP(hr, error);\r
}\r
else\r
{\r
WCHAR *pszDeviceId = NULL;\r
- hResult = IMMDevice_GetId(defaultRenderer, &pszDeviceId);\r
- IF_FAILED_JUMP(hResult, error);\r
+ hr = IMMDevice_GetId(defaultRenderer, &pszDeviceId);\r
+ IF_FAILED_JUMP(hr, error);\r
wcsncpy(paWasapi->defaultRenderer, pszDeviceId, MAX_STR_LEN-1);\r
CoTaskMemFree(pszDeviceId);\r
IMMDevice_Release(defaultRenderer);\r
\r
{\r
IMMDevice *defaultCapturer = NULL;\r
- hResult = IMMDeviceEnumerator_GetDefaultAudioEndpoint(paWasapi->enumerator, eCapture, eMultimedia, &defaultCapturer);\r
- if (hResult != S_OK)\r
+ hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(paWasapi->enumerator, eCapture, eMultimedia, &defaultCapturer);\r
+ if (hr != S_OK)\r
{\r
- if (hResult != E_NOTFOUND)\r
- IF_FAILED_JUMP(hResult, error);\r
+ if (hr != E_NOTFOUND)\r
+ IF_FAILED_JUMP(hr, error);\r
}\r
else\r
{\r
WCHAR *pszDeviceId = NULL;\r
- hResult = IMMDevice_GetId(defaultCapturer, &pszDeviceId);\r
- IF_FAILED_JUMP(hResult, error);\r
+ hr = IMMDevice_GetId(defaultCapturer, &pszDeviceId);\r
+ IF_FAILED_JUMP(hr, error);\r
wcsncpy(paWasapi->defaultCapturer, pszDeviceId, MAX_STR_LEN-1);\r
CoTaskMemFree(pszDeviceId);\r
IMMDevice_Release(defaultCapturer);\r
}\r
}\r
\r
- hResult = IMMDeviceEnumerator_EnumAudioEndpoints(paWasapi->enumerator, eAll, DEVICE_STATE_ACTIVE, &pEndPoints);\r
- IF_FAILED_JUMP(hResult, error);\r
+ hr = IMMDeviceEnumerator_EnumAudioEndpoints(paWasapi->enumerator, eAll, DEVICE_STATE_ACTIVE, &pEndPoints);\r
+ IF_FAILED_JUMP(hr, error);\r
\r
- hResult = IMMDeviceCollection_GetCount(pEndPoints, &paWasapi->deviceCount);\r
- IF_FAILED_JUMP(hResult, error);\r
+ hr = IMMDeviceCollection_GetCount(pEndPoints, &paWasapi->deviceCount);\r
+ IF_FAILED_JUMP(hr, error);\r
\r
paWasapi->devInfo = (PaWasapiDeviceInfo *)malloc(sizeof(PaWasapiDeviceInfo) * paWasapi->deviceCount);\r
for (i = 0; i < paWasapi->deviceCount; ++i)\r
\r
PA_DEBUG(("WASAPI: device i: %d\n", i));\r
\r
- hResult = IMMDeviceCollection_Item(pEndPoints, i, &paWasapi->devInfo[i].device);\r
- IF_FAILED_JUMP(hResult, error);\r
+ hr = IMMDeviceCollection_Item(pEndPoints, i, &paWasapi->devInfo[i].device);\r
+ IF_FAILED_JUMP(hr, error);\r
\r
// getting ID\r
{\r
WCHAR *pszDeviceId = NULL;\r
- hResult = IMMDevice_GetId(paWasapi->devInfo[i].device, &pszDeviceId);\r
- IF_FAILED_JUMP(hResult, error);\r
+ hr = IMMDevice_GetId(paWasapi->devInfo[i].device, &pszDeviceId);\r
+ IF_FAILED_JUMP(hr, error);\r
wcsncpy(paWasapi->devInfo[i].szDeviceID, pszDeviceId, MAX_STR_LEN-1);\r
CoTaskMemFree(pszDeviceId);\r
\r
}\r
}\r
\r
- hResult = IMMDevice_GetState(paWasapi->devInfo[i].device, &paWasapi->devInfo[i].state);\r
- IF_FAILED_JUMP(hResult, error);\r
+ hr = IMMDevice_GetState(paWasapi->devInfo[i].device, &paWasapi->devInfo[i].state);\r
+ IF_FAILED_JUMP(hr, error);\r
\r
if (paWasapi->devInfo[i].state != DEVICE_STATE_ACTIVE)\r
{\r
\r
{\r
IPropertyStore *pProperty;\r
- hResult = IMMDevice_OpenPropertyStore(paWasapi->devInfo[i].device, STGM_READ, &pProperty);\r
- IF_FAILED_JUMP(hResult, error);\r
+ hr = IMMDevice_OpenPropertyStore(paWasapi->devInfo[i].device, STGM_READ, &pProperty);\r
+ IF_FAILED_JUMP(hr, error);\r
\r
// "Friendly" Name\r
{\r
char *deviceName;\r
PROPVARIANT value;\r
PropVariantInit(&value);\r
- hResult = IPropertyStore_GetValue(pProperty, &PKEY_Device_FriendlyName, &value);\r
- IF_FAILED_JUMP(hResult, error);\r
+ hr = IPropertyStore_GetValue(pProperty, &PKEY_Device_FriendlyName, &value);\r
+ IF_FAILED_JUMP(hr, error);\r
deviceInfo->name = NULL;\r
deviceName = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1);\r
if (deviceName == NULL)\r
{\r
PROPVARIANT value;\r
PropVariantInit(&value);\r
- hResult = IPropertyStore_GetValue(pProperty, &PKEY_AudioEngine_DeviceFormat, &value);\r
- IF_FAILED_JUMP(hResult, error);\r
+ hr = IPropertyStore_GetValue(pProperty, &PKEY_AudioEngine_DeviceFormat, &value);\r
+ IF_FAILED_JUMP(hr, error);\r
memcpy(&paWasapi->devInfo[i].DefaultFormat, value.blob.pBlobData, min(sizeof(paWasapi->devInfo[i].DefaultFormat), value.blob.cbSize));\r
// cleanup\r
PropVariantClear(&value);\r
{\r
PROPVARIANT value;\r
PropVariantInit(&value);\r
- hResult = IPropertyStore_GetValue(pProperty, &PKEY_AudioEndpoint_FormFactor, &value);\r
- IF_FAILED_JUMP(hResult, error);\r
+ hr = IPropertyStore_GetValue(pProperty, &PKEY_AudioEndpoint_FormFactor, &value);\r
+ IF_FAILED_JUMP(hr, error);\r
// set\r
#if defined(DUMMYUNIONNAME) && defined(NONAMELESSUNION)\r
// avoid breaking strict-aliasing rules in such line: (EndpointFormFactor)(*((UINT *)(((WORD *)&value.wReserved3)+1)));\r
// Endpoint data\r
{\r
IMMEndpoint *endpoint = NULL;\r
- hResult = IMMDevice_QueryInterface(paWasapi->devInfo[i].device, &pa_IID_IMMEndpoint, (void **)&endpoint);\r
- if (SUCCEEDED(hResult))\r
+ hr = IMMDevice_QueryInterface(paWasapi->devInfo[i].device, &pa_IID_IMMEndpoint, (void **)&endpoint);\r
+ if (SUCCEEDED(hr))\r
{\r
- hResult = IMMEndpoint_GetDataFlow(endpoint, &paWasapi->devInfo[i].flow);\r
+ hr = IMMEndpoint_GetDataFlow(endpoint, &paWasapi->devInfo[i].flow);\r
SAFE_RELEASE(endpoint);\r
}\r
}\r
{\r
IAudioClient *tmpClient = NULL;\r
\r
- hResult = IMMDevice_Activate(paWasapi->devInfo[i].device, &pa_IID_IAudioClient,\r
+ hr = IMMDevice_Activate(paWasapi->devInfo[i].device, &pa_IID_IAudioClient,\r
CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient);\r
- IF_FAILED_JUMP(hResult, error);\r
+ IF_FAILED_JUMP(hr, error);\r
\r
- hResult = IAudioClient_GetDevicePeriod(tmpClient,\r
+ hr = IAudioClient_GetDevicePeriod(tmpClient,\r
&paWasapi->devInfo[i].DefaultDevicePeriod,\r
&paWasapi->devInfo[i].MinimumDevicePeriod);\r
- IF_FAILED_JUMP(hResult, error);\r
+ IF_FAILED_JUMP(hr, error);\r
\r
- //hResult = tmpClient->GetMixFormat(&paWasapi->devInfo[i].MixFormat);\r
+ //hr = tmpClient->GetMixFormat(&paWasapi->devInfo[i].MixFormat);\r
\r
// Release client\r
SAFE_RELEASE(tmpClient);\r
\r
- if (hResult != S_OK)\r
+ if (hr != S_OK)\r
{\r
//davidv: this happened with my hardware, previously for that same device in DirectSound:\r
//Digital Output (Realtek AC'97 Audio)'s GUID: {0x38f2cf50,0x7b4c,0x4740,0x86,0xeb,0xd4,0x38,0x66,0xd8,0xc8, 0x9f}\r
//so something must be _really_ wrong with this device, TODO handle this better. We kind of need GetMixFormat\r
- LogHostError(hResult);\r
+ LogHostError(hr);\r
goto error;\r
}\r
}\r
\r
SAFE_RELEASE(pEndPoints);\r
\r
+ PRINT(("WASAPI: initialized ok"));\r
+\r
return paNoError;\r
\r
error:\r
\r
+ PRINT(("WASAPI: failed %s error[%d|%s]", __FUNCTION__, result, Pa_GetErrorText(result)));\r
+\r
SAFE_RELEASE(pEndPoints);\r
\r
Terminate((PaUtilHostApiRepresentation *)paWasapi);\r
}\r
free(paWasapi->devInfo);\r
\r
- CoUninitialize();\r
-\r
if (paWasapi->allocations)\r
{\r
PaUtil_FreeAllAllocations(paWasapi->allocations);\r
\r
// Close AVRT\r
CloseAVRT();\r
+\r
+ // Uninit COM\r
+ if (g_bCOMInitialized)\r
+ CoUninitialize();\r
}\r
\r
// ------------------------------------------------------------------------------------------\r
{\r
PaError answer = paInvalidSampleRate;\r
WAVEFORMATEX *sharedClosestMatch = NULL;\r
- HRESULT hResult = !S_OK;\r
+ HRESULT hr = !S_OK;\r
\r
MakeWaveFormatFromParams(outWavex, params, sampleRate);\r
\r
- hResult = IAudioClient_IsFormatSupported(myClient, shareMode, &outWavex->Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));\r
- if (hResult == S_OK)\r
+ hr = IAudioClient_IsFormatSupported(myClient, shareMode, &outWavex->Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));\r
+ if (hr == S_OK)\r
answer = paFormatIsSupported;\r
else\r
if (sharedClosestMatch)\r
WAVEFORMATEXTENSIBLE ext = { 0 };\r
wasapiFillWFEXT(&ext,BestToWorst[i],sampleRate,params->channelCount);\r
\r
- hResult = IAudioClient_IsFormatSupported(myClient, shareMode, &ext.Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));\r
- if (hResult == S_OK)\r
+ hr = IAudioClient_IsFormatSupported(myClient, shareMode, &ext.Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));\r
+ if (hr == S_OK)\r
{\r
memcpy(outWavex,&ext,sizeof(WAVEFORMATEXTENSIBLE));\r
answer = paFormatIsSupported;\r
pcm16WaveFormat.wBitsPerSample = 16;\r
pcm16WaveFormat.cbSize = 0;\r
\r
- hResult = IAudioClient_IsFormatSupported(myClient, shareMode, &pcm16WaveFormat, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));\r
- if (hResult == S_OK)\r
+ hr = IAudioClient_IsFormatSupported(myClient, shareMode, &pcm16WaveFormat, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));\r
+ if (hr == S_OK)\r
{\r
memcpy(outWavex,&pcm16WaveFormat,sizeof(WAVEFORMATEX));\r
answer = paFormatIsSupported;\r
}\r
}\r
\r
- LogHostError(hResult);\r
+ LogHostError(hr);\r
}\r
\r
return answer;\r
if (inputParameters != NULL)\r
{\r
WAVEFORMATEXTENSIBLE wavex;\r
- HRESULT hResult;\r
+ HRESULT hr;\r
PaError answer;\r
AUDCLNT_SHAREMODE shareMode = AUDCLNT_SHAREMODE_SHARED;\r
inputStreamInfo = (PaWasapiStreamInfo *)inputParameters->hostApiSpecificStreamInfo;\r
if (inputStreamInfo && (inputStreamInfo->flags & paWinWasapiExclusive))\r
shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;\r
\r
- hResult = IMMDevice_Activate(paWasapi->devInfo[inputParameters->device].device,\r
+ hr = IMMDevice_Activate(paWasapi->devInfo[inputParameters->device].device,\r
&pa_IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient);\r
- if (hResult != S_OK)\r
+ if (hr != S_OK)\r
{\r
- LogHostError(hResult);\r
+ LogHostError(hr);\r
return paInvalidDevice;\r
}\r
\r
\r
if (outputParameters != NULL)\r
{\r
- HRESULT hResult;\r
+ HRESULT hr;\r
WAVEFORMATEXTENSIBLE wavex;\r
PaError answer;\r
AUDCLNT_SHAREMODE shareMode = AUDCLNT_SHAREMODE_SHARED;\r
if (outputStreamInfo && (outputStreamInfo->flags & paWinWasapiExclusive))\r
shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE;\r
\r
- hResult = IMMDevice_Activate(paWasapi->devInfo[outputParameters->device].device,\r
+ hr = IMMDevice_Activate(paWasapi->devInfo[outputParameters->device].device,\r
&pa_IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient);\r
- if (hResult != S_OK)\r
+ if (hr != S_OK)\r
{\r
- LogHostError(hResult);\r
+ LogHostError(hr);\r
return paInvalidDevice;\r
}\r
\r
\r
// Create volume mgr\r
stream->inVol = NULL;\r
- /*hResult = info->device->Activate(\r
+ /*hr = info->device->Activate(\r
__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL,\r
(void**)&stream->inVol);\r
- if (hResult != S_OK)\r
+ if (hr != S_OK)\r
return paInvalidDevice;*/\r
\r
// Set user-side custom host processor\r
\r
// Activate volume\r
stream->outVol = NULL;\r
- /*hResult = info->device->Activate(\r
+ /*hr = info->device->Activate(\r
__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL,\r
(void**)&stream->outVol);\r
- if (hResult != S_OK)\r
+ if (hr != S_OK)\r
return paInvalidDevice;*/\r
\r
// Set user-side custom host processor\r
PaStreamCallbackFlags flags = 0;\r
int callbackResult;\r
unsigned long framesProcessed;\r
- HRESULT hResult;\r
+ HRESULT hr;\r
UINT32 pending;\r
\r
PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );\r
if (stream->in.client != NULL)\r
{\r
PaTime pending_time;\r
- if ((hResult = IAudioClient_GetCurrentPadding(stream->in.client, &pending)) == S_OK)\r
+ if ((hr = IAudioClient_GetCurrentPadding(stream->in.client, &pending)) == S_OK)\r
pending_time = (PaTime)pending / (PaTime)stream->in.wavex.Format.nSamplesPerSec;\r
else\r
pending_time = (PaTime)stream->in.latency_seconds;\r
if (stream->out.client != NULL)\r
{\r
PaTime pending_time;\r
- if ((hResult = IAudioClient_GetCurrentPadding(stream->out.client, &pending)) == S_OK)\r
+ if ((hr = IAudioClient_GetCurrentPadding(stream->out.client, &pending)) == S_OK)\r
pending_time = (PaTime)pending / (PaTime)stream->out.wavex.Format.nSamplesPerSec;\r
else\r
pending_time = (PaTime)stream->out.latency_seconds;\r