IAudioRenderClient *rclient;\r
IAudioEndpointVolume *outVol;\r
\r
+ // event handles for event-driven processing mode\r
+ HANDLE event[S_COUNT];\r
+\r
// must be volatile to avoid race condition on user query while\r
// thread is being started\r
volatile BOOL running;\r
return result;\r
}\r
\r
- SAFE_RELEASE(stream->out.client);\r
- SAFE_RELEASE(stream->in.client);\r
SAFE_RELEASE(stream->cclient);\r
SAFE_RELEASE(stream->rclient);\r
+ SAFE_RELEASE(stream->out.client);\r
+ SAFE_RELEASE(stream->in.client);\r
SAFE_RELEASE(stream->inVol);\r
SAFE_RELEASE(stream->outVol);\r
\r
+ CloseHandle(stream->event[S_INPUT]);\r
+ CloseHandle(stream->event[S_OUTPUT]);\r
+\r
SAFE_CLOSE(stream->hThread);\r
SAFE_CLOSE(stream->hThreadStart);\r
SAFE_CLOSE(stream->hThreadExit);\r
stream->hThreadStart = CreateEvent(NULL, TRUE, FALSE, NULL);\r
stream->hThreadExit = CreateEvent(NULL, TRUE, FALSE, NULL);\r
\r
- if ((stream->in.client && stream->in.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) ||\r
- (stream->out.client && stream->out.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))\r
+ if ((stream->in.client && (stream->in.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)) ||\r
+ (stream->out.client && (stream->out.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)))\r
{\r
if ((stream->hThread = CREATE_THREAD(ProcThreadEvent)) == NULL)\r
return paUnanticipatedHostError;\r
// Stop INPUT client\r
if (stream->in.client != NULL)\r
IAudioClient_Stop(stream->in.client);\r
+\r
// Stop OUTPUT client\r
if (stream->out.client != NULL)\r
IAudioClient_Stop(stream->out.client);\r
// ------------------------------------------------------------------------------------------\r
PA_THREAD_FUNC ProcThreadEvent(void *param)\r
{\r
- HANDLE event[S_COUNT];\r
PaWasapiHostProcessor processor[S_COUNT];\r
HRESULT hr;\r
DWORD dwResult;\r
processor[S_INPUT] = (stream->hostProcessOverrideInput.processor != NULL ? stream->hostProcessOverrideInput : defaultProcessor);\r
processor[S_OUTPUT] = (stream->hostProcessOverrideOutput.processor != NULL ? stream->hostProcessOverrideOutput : defaultProcessor);\r
\r
- // Initialize event to NULL first\r
- event[S_INPUT] = CreateEvent(NULL, FALSE, FALSE, NULL);\r
- event[S_OUTPUT] = CreateEvent(NULL, FALSE, FALSE, NULL);\r
-\r
- // Check on low resources and disallow any processing further\r
- if (!event[S_INPUT] || !event[S_OUTPUT])\r
- {\r
- PRINT(("WASAPI Thread: failed creating one or two event handles\n"));\r
-\r
- // Prevent deadlocking in Pa_StreamStart\r
- SetEvent(stream->hThreadStart);\r
- // Exit\r
- goto thread_end;\r
- }\r
-\r
// Boost thread priority\r
PaWasapi_ThreadPriorityBoost((void **)&stream->hAvTask, stream->nThreadPriority);\r
\r
// Initialize event & start INPUT stream\r
if (stream->in.client)\r
{\r
- if ((hr = IAudioClient_SetEventHandle(stream->in.client, event[S_INPUT])) != S_OK)\r
- LogHostError(hr);\r
+ // Create & set handle\r
+ if (stream->event[S_INPUT] == NULL)\r
+ {\r
+ stream->event[S_INPUT] = CreateEvent(NULL, FALSE, FALSE, NULL);\r
+ if (stream->event[S_INPUT] == NULL)\r
+ {\r
+ PRINT(("WASAPI Thread: failed creating Input event handle\n"));\r
+ goto thread_error;\r
+ }\r
+ if ((hr = IAudioClient_SetEventHandle(stream->in.client, stream->event[S_INPUT])) != S_OK)\r
+ {\r
+ LogHostError(hr);\r
+ goto thread_error;\r
+ }\r
+ }\r
\r
- if ((hr = IAudioClient_GetService(stream->in.client, &pa_IID_IAudioCaptureClient, (void **)&stream->cclient)) != S_OK)\r
- LogHostError(hr);\r
+ // Create Capture client\r
+ if (stream->cclient == NULL)\r
+ {\r
+ if ((hr = IAudioClient_GetService(stream->in.client, &pa_IID_IAudioCaptureClient, (void **)&stream->cclient)) != S_OK)\r
+ {\r
+ LogHostError(hr);\r
+ goto thread_error;\r
+ }\r
+ }\r
\r
+ // Start\r
if ((hr = IAudioClient_Start(stream->in.client)) != S_OK)\r
+ {\r
LogHostError(hr);\r
+ goto thread_error;\r
+ }\r
}\r
\r
// Initialize event & start OUTPUT stream\r
if (stream->out.client)\r
{\r
- if ((hr = IAudioClient_SetEventHandle(stream->out.client, event[S_OUTPUT])) != S_OK)\r
- LogHostError(hr);\r
+ // Create & set handle\r
+ if (stream->event[S_OUTPUT] == NULL)\r
+ {\r
+ stream->event[S_OUTPUT] = CreateEvent(NULL, FALSE, FALSE, NULL);\r
+ if (stream->event[S_OUTPUT] == NULL)\r
+ {\r
+ PRINT(("WASAPI Thread: failed creating Output event handle\n"));\r
+ goto thread_error;\r
+ }\r
\r
- if ((hr = IAudioClient_GetService(stream->out.client, &pa_IID_IAudioRenderClient, (void **)&stream->rclient)) != S_OK)\r
- LogHostError(hr);\r
+ if ((hr = IAudioClient_SetEventHandle(stream->out.client, stream->event[S_OUTPUT])) != S_OK)\r
+ {\r
+ LogHostError(hr);\r
+ goto thread_error;\r
+ }\r
+ }\r
+\r
+ // Create Render client\r
+ if (stream->rclient == NULL)\r
+ {\r
+ if ((hr = IAudioClient_GetService(stream->out.client, &pa_IID_IAudioRenderClient, (void **)&stream->rclient)) != S_OK)\r
+ {\r
+ LogHostError(hr);\r
+ goto thread_error;\r
+ }\r
+ }\r
\r
// Preload buffer before start\r
if ((hr = FillOutputBuffer(stream, processor, stream->out.framesPerHostCallback)) != S_OK)\r
+ {\r
LogHostError(hr);\r
+ goto thread_error;\r
+ }\r
\r
// Start\r
if ((hr = IAudioClient_Start(stream->out.client)) != S_OK)\r
+ {\r
LogHostError(hr);\r
+ goto thread_error;\r
+ }\r
+\r
}\r
\r
// Signal: stream running\r
for (;;)\r
{\r
// 2 sec timeout\r
- dwResult = WaitForMultipleObjects(S_COUNT, event, bWaitAllEvents, 10000);\r
+ dwResult = WaitForMultipleObjects(S_COUNT, stream->event, bWaitAllEvents, 10000);\r
\r
// Check for close event (after wait for buffers to avoid any calls to user\r
// callback when hCloseRequest was set)\r
{\r
case WAIT_TIMEOUT: {\r
PRINT(("WASAPI Thread: WAIT_TIMEOUT - probably bad audio driver or Vista x64 bug: use paWinWasapiPolling instead\n"));\r
- goto processing_stop;\r
+ goto thread_end;\r
break; }\r
\r
// Input stream\r
}\r
}\r
\r
-processing_stop:\r
+thread_end:\r
\r
// Process stop\r
_OnStreamStop(stream);\r
\r
-thread_end:\r
-\r
- // Close event\r
- CloseHandle(event[S_INPUT]);\r
- CloseHandle(event[S_OUTPUT]);\r
-\r
// Notify: thread exited\r
SetEvent(stream->hThreadExit);\r
\r
stream->running = FALSE;\r
\r
return 0;\r
+\r
+thread_error:\r
+\r
+ // Prevent deadlocking in Pa_StreamStart\r
+ SetEvent(stream->hThreadStart);\r
+\r
+ // Exit\r
+ goto thread_end;\r
}\r
\r
// ------------------------------------------------------------------------------------------\r
// Initialize event & start INPUT stream\r
if (stream->in.client)\r
{\r
- if ((hr = IAudioClient_GetService(stream->in.client, &pa_IID_IAudioCaptureClient, (void **)&stream->cclient)) != S_OK)\r
- LogHostError(hr);\r
+ if (stream->cclient == NULL)\r
+ {\r
+ if ((hr = IAudioClient_GetService(stream->in.client, &pa_IID_IAudioCaptureClient, (void **)&stream->cclient)) != S_OK)\r
+ {\r
+ LogHostError(hr);\r
+ goto thread_error;\r
+ }\r
+ }\r
\r
if ((hr = IAudioClient_Start(stream->in.client)) != S_OK)\r
+ {\r
LogHostError(hr);\r
+ goto thread_error;\r
+ }\r
}\r
\r
\r
// Initialize event & start OUTPUT stream\r
if (stream->out.client)\r
{\r
- if ((hr = IAudioClient_GetService(stream->out.client, &pa_IID_IAudioRenderClient, (void **)&stream->rclient)) != S_OK)\r
- LogHostError(hr);\r
+ if (stream->rclient == NULL)\r
+ {\r
+ if ((hr = IAudioClient_GetService(stream->out.client, &pa_IID_IAudioRenderClient, (void **)&stream->rclient)) != S_OK)\r
+ {\r
+ LogHostError(hr);\r
+ goto thread_error;\r
+ }\r
+ }\r
\r
// Preload buffer (obligatory, othervise ->Start() will fail)\r
if ((hr = FillOutputBuffer(stream, processor, stream->out.framesPerHostCallback)) != S_OK)\r
+ {\r
LogHostError(hr);\r
+ goto thread_error;\r
+ }\r
\r
// Start\r
if ((hr = IAudioClient_Start(stream->out.client)) != S_OK)\r
+ {\r
LogHostError(hr);\r
+ goto thread_error;\r
+ }\r
}\r
\r
// Signal: stream running\r
}\r
}\r
\r
+thread_end:\r
+\r
// Process stop\r
_OnStreamStop(stream);\r
\r
stream->running = FALSE;\r
\r
return 0;\r
+\r
+thread_error:\r
+\r
+ // Prevent deadlocking in Pa_StreamStart\r
+ SetEvent(stream->hThreadStart);\r
+\r
+ // Exit\r
+ goto thread_end;\r
}\r
\r
//#endif //VC 2005\r