]> Repos - portaudio/commitdiff
wasapi:
authordmitrykos <dmitrykos@0f58301d-fd10-0410-b4af-bbb618454e57>
Mon, 17 May 2010 18:37:00 +0000 (18:37 +0000)
committerdmitrykos <dmitrykos@0f58301d-fd10-0410-b4af-bbb618454e57>
Mon, 17 May 2010 18:37:00 +0000 (18:37 +0000)
 - fixed object (IAudioRenderClient/IAudioCaptureClient) leak if stream is stopped and restarted without closing
 - improved IAudioClient event handle management on stream restart (not deleting/creating event handle but rather keeping it until stream is closed)

src/hostapi/wasapi/pa_win_wasapi.c

index 6103c34536d890b5153be1f99f3e1dc714aa4320..46651299ba5f767e386733a25718d8c74a79ac44 100644 (file)
@@ -512,6 +512,9 @@ typedef struct PaWasapiStream
     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
@@ -2527,13 +2530,16 @@ static PaError CloseStream( PaStream* s )
                        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
@@ -2573,8 +2579,8 @@ static PaError StartStream( PaStream *s )
                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
@@ -3292,6 +3298,7 @@ void _OnStreamStop(PaWasapiStream *stream)
        // 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
@@ -3311,7 +3318,6 @@ void _OnStreamStop(PaWasapiStream *stream)
 // ------------------------------------------------------------------------------------------\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
@@ -3332,53 +3338,90 @@ PA_THREAD_FUNC ProcThreadEvent(void *param)
     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
@@ -3391,7 +3434,7 @@ PA_THREAD_FUNC ProcThreadEvent(void *param)
        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
@@ -3403,7 +3446,7 @@ PA_THREAD_FUNC ProcThreadEvent(void *param)
                {\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
@@ -3422,17 +3465,11 @@ PA_THREAD_FUNC ProcThreadEvent(void *param)
                }\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
@@ -3440,6 +3477,14 @@ thread_end:
        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
@@ -3474,27 +3519,48 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
        // 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
@@ -3547,6 +3613,8 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
                }\r
        }\r
 \r
+thread_end:\r
+\r
        // Process stop\r
        _OnStreamStop(stream);\r
 \r
@@ -3557,6 +3625,14 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
        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