- implemented support of non-Interlieved buffers (paNonInterleaved) for WASAPI blocking interface for input and output
 - blocking methods will now use PA sample converters
This commit is contained in:
dmitrykos 2010-05-31 09:46:49 +00:00
commit 3e700ec6d2

View file

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