]> Repos - portaudio/commitdiff
wasapi:
authordmitrykos <dmitrykos@0f58301d-fd10-0410-b4af-bbb618454e57>
Mon, 31 May 2010 09:46:49 +0000 (09:46 +0000)
committerdmitrykos <dmitrykos@0f58301d-fd10-0410-b4af-bbb618454e57>
Mon, 31 May 2010 09:46:49 +0000 (09:46 +0000)
 - implemented support of non-Interlieved buffers (paNonInterleaved) for WASAPI blocking interface for input and output
 - blocking methods will now use PA sample converters

src/hostapi/wasapi/pa_win_wasapi.c

index 3ae9a0dbd16809fd30d1ac47c12a2daf5c1a4c0b..185715098cd9339bafe5188b708be46f8ed59837 100644 (file)
        #include <functiondiscoverykeys.h>\r
        #undef INITGUID\r
 #endif\r
+#ifndef __MWERKS__\r
+#include <malloc.h>\r
+#include <memory.h>\r
+#endif /* __MWERKS__ */\r
 \r
 #include "pa_util.h"\r
 #include "pa_allocation.h"\r
@@ -2741,10 +2745,10 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long _frames )
 \r
        HRESULT hr = S_OK;\r
        UINT32 frames;\r
-       BYTE *buffer = (BYTE *)_buffer;\r
-       BYTE *data = NULL;\r
+       BYTE *user_buffer = (BYTE *)_buffer;\r
+       BYTE *wasapi_buffer = NULL;\r
        DWORD flags = 0;\r
-       UINT32 buffer_size;\r
+       UINT32 i;\r
 \r
        // validate\r
        if (!stream->running)\r
@@ -2755,10 +2759,24 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long _frames )
        // Notify blocking op has begun\r
        ResetEvent(stream->hBlockingOpStreamRD);\r
 \r
+    // make a local copy of the user buffer pointer(s), this is necessary\r
+       // because PaUtil_CopyOutput() advances these pointers every time it is called\r
+    if (!stream->bufferProcessor.userInputIsInterleaved)\r
+    {\r
+               user_buffer = (BYTE *)alloca(sizeof(BYTE *) * stream->bufferProcessor.inputChannelCount);\r
+        if (user_buffer == NULL)\r
+            return paInsufficientMemory;\r
+\r
+        for (i = 0; i < stream->bufferProcessor.inputChannelCount; ++i)\r
+            ((BYTE **)user_buffer)[i] = ((BYTE **)_buffer)[i];\r
+    }\r
+\r
        while (_frames != 0)\r
        {\r
+               UINT32 processed, processed_size;\r
+\r
                // Get the available data in the shared buffer.\r
-               if ((hr = IAudioCaptureClient_GetBuffer(stream->cclient, &data, &frames, &flags, NULL, NULL)) != S_OK)\r
+               if ((hr = IAudioCaptureClient_GetBuffer(stream->cclient, &wasapi_buffer, &frames, &flags, NULL, NULL)) != S_OK)\r
                {\r
                        if (hr == AUDCLNT_S_BUFFER_EMPTY)\r
                        {\r
@@ -2779,19 +2797,35 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long _frames )
                if (frames > _frames)\r
                        frames = _frames;\r
 \r
-               // Copy\r
-               buffer_size = frames * stream->in.wavex.Format.nBlockAlign;\r
-               memcpy(buffer, data, buffer_size);\r
-               buffer += buffer_size;\r
+               // Register available frames to processor\r
+        PaUtil_SetInputFrameCount(&stream->bufferProcessor, frames);\r
+               \r
+               // Register host buffer pointer to processor\r
+        PaUtil_SetInterleavedInputChannels(&stream->bufferProcessor, 0, wasapi_buffer, stream->bufferProcessor.inputChannelCount);\r
+               \r
+               // Copy user data to host buffer (with conversion if applicable)\r
+               processed = PaUtil_CopyInput(&stream->bufferProcessor, (void **)&user_buffer, frames);\r
 \r
-               // Release buffer\r
-               if ((hr = IAudioCaptureClient_ReleaseBuffer(stream->cclient, frames)) != S_OK)\r
+               // Advance user buffer to consumed portion\r
+               processed_size = processed * stream->in.wavex.Format.nBlockAlign;\r
+               if (stream->bufferProcessor.userInputIsInterleaved)\r
+               {\r
+                       user_buffer += processed_size;\r
+               }\r
+               else\r
+               {\r
+                       for (i = 0; i < stream->bufferProcessor.inputChannelCount; ++i)\r
+                               ((BYTE **)user_buffer)[i] = ((BYTE **)user_buffer)[i] + processed_size;\r
+               }\r
+\r
+               // Release host buffer\r
+               if ((hr = IAudioCaptureClient_ReleaseBuffer(stream->cclient, processed)) != S_OK)\r
                {\r
                        LogHostError(hr);\r
                        goto stream_rd_end;\r
                }\r
 \r
-               _frames -= frames;\r
+               _frames -= processed;\r
        }\r
 \r
 stream_rd_end:\r
@@ -2808,8 +2842,8 @@ static PaError WriteStream( PaStream* s, const void *_buffer, unsigned long _fra
     PaWasapiStream *stream = (PaWasapiStream*)s;\r
 \r
        UINT32 frames;\r
-       const BYTE *buffer = (BYTE *)_buffer;\r
-       BYTE *data;\r
+       const BYTE *user_buffer = (const BYTE *)_buffer;\r
+       BYTE *wasapi_buffer;\r
        HRESULT hr = S_OK;\r
        UINT32 next_rev_sleep, blocks, block_sleep_ms;\r
        UINT32 i;\r
@@ -2854,11 +2888,22 @@ static PaError WriteStream( PaStream* s, const void *_buffer, unsigned long _fra
                Sleep(stream->out.prevSleep);\r
        stream->out.prevSleep = next_rev_sleep;\r
 \r
+    // make a local copy of the user buffer pointer(s), this is necessary\r
+       // because PaUtil_CopyOutput() advances these pointers every time it is called\r
+    if (!stream->bufferProcessor.userOutputIsInterleaved)\r
+    {\r
+        user_buffer = (const BYTE *)alloca(sizeof(const BYTE *) * stream->bufferProcessor.outputChannelCount);\r
+        if (user_buffer == NULL)\r
+            return paInsufficientMemory;\r
+\r
+        for (i = 0; i < stream->bufferProcessor.outputChannelCount; ++i)\r
+            ((const BYTE **)user_buffer)[i] = ((const BYTE **)_buffer)[i];\r
+    }\r
+\r
        // Feed engine\r
        for (i = 0; i < blocks; ++i)\r
        {\r
-               UINT32 available;\r
-               UINT32 buffer_size;\r
+               UINT32 available, processed;\r
 \r
                // Get block frames\r
                frames = stream->out.framesPerHostCallback;\r
@@ -2871,6 +2916,7 @@ static PaError WriteStream( PaStream* s, const void *_buffer, unsigned long _fra
                while (frames != 0)\r
                {\r
                        UINT32 padding = 0;\r
+                       UINT32 processed_size;\r
 \r
                        // Check if blocking call must be interrupted\r
                        if (WaitForSingleObject(stream->hCloseRequest, 0) != WAIT_TIMEOUT)\r
@@ -2884,14 +2930,14 @@ static PaError WriteStream( PaStream* s, const void *_buffer, unsigned long _fra
                                goto stream_wr_end;\r
                        }\r
 \r
-                       // Get frames available\r
+                       // Calculate frames available\r
                        if (frames >= padding)\r
                                available = frames - padding;\r
                        else\r
                                available = frames;\r
 \r
-                       // Get buffer\r
-                       if ((hr = IAudioRenderClient_GetBuffer(stream->rclient, available, &data)) != S_OK)\r
+                       // Get pointer to host buffer\r
+                       if ((hr = IAudioRenderClient_GetBuffer(stream->rclient, available, &wasapi_buffer)) != S_OK)\r
                        {\r
                                // Buffer size is too big, waiting\r
                                if (hr == AUDCLNT_E_BUFFER_TOO_LARGE)\r
@@ -2900,19 +2946,36 @@ static PaError WriteStream( PaStream* s, const void *_buffer, unsigned long _fra
                                goto stream_wr_end;\r
                        }\r
 \r
-                       // Copy\r
-                       buffer_size = available * stream->out.wavex.Format.nBlockAlign;\r
-                       memcpy(data, buffer, buffer_size);\r
-                       buffer += buffer_size;\r
+                       // Register available frames to processor\r
+            PaUtil_SetOutputFrameCount(&stream->bufferProcessor, available);\r
+                       \r
+                       // Register host buffer pointer to processor\r
+            PaUtil_SetInterleavedOutputChannels(&stream->bufferProcessor, 0, wasapi_buffer,    stream->bufferProcessor.outputChannelCount);\r
+                       \r
+                       // Copy user data to host buffer (with conversion if applicable)\r
+                       processed = PaUtil_CopyOutput(&stream->bufferProcessor, (const void **)&user_buffer, available);\r
+\r
+                       // Advance user buffer to consumed portion\r
+                       processed_size = processed * stream->out.wavex.Format.nBlockAlign;\r
+                       if (stream->bufferProcessor.userOutputIsInterleaved)\r
+                       {\r
+                               user_buffer += processed_size;\r
+                       }\r
+                       else\r
+                       {\r
+                               for (i = 0; i < stream->bufferProcessor.outputChannelCount; ++i)\r
+                                       ((const BYTE **)user_buffer)[i] = ((const BYTE **)user_buffer)[i] + processed_size;\r
+                       }\r
 \r
-                       // Release buffer\r
-                       if ((hr = IAudioRenderClient_ReleaseBuffer(stream->rclient, available, 0)) != S_OK)\r
+                       // Release host buffer\r
+                       if ((hr = IAudioRenderClient_ReleaseBuffer(stream->rclient, processed, 0)) != S_OK)\r
                        {\r
                                LogHostError(hr);\r
                                goto stream_wr_end;\r
                        }\r
 \r
-                       frames -= available;\r
+                       // Deduct frames\r
+                       frames -= processed;\r
                }\r
 \r
                _frames -= frames;\r