Roll-up of SVN hotplug branch at most recent revision (r1677), based at the same point in the master revision history as it was originally applied.
This commit is contained in:
parent
8d0c648b7d
commit
d13fcd8ea9
27 changed files with 2117 additions and 1435 deletions
|
|
@ -76,20 +76,20 @@
|
|||
#include "pa_ringbuffer.h"
|
||||
|
||||
#ifndef NTDDI_VERSION
|
||||
|
||||
|
||||
#undef WINVER
|
||||
#undef _WIN32_WINNT
|
||||
#define WINVER 0x0600 // VISTA
|
||||
#define _WIN32_WINNT WINVER
|
||||
|
||||
#ifndef _AVRT_ //<< fix MinGW dummy compile by defining missing type: AVRT_PRIORITY
|
||||
typedef enum _AVRT_PRIORITY
|
||||
{
|
||||
AVRT_PRIORITY_LOW = -1,
|
||||
AVRT_PRIORITY_NORMAL,
|
||||
AVRT_PRIORITY_HIGH,
|
||||
AVRT_PRIORITY_CRITICAL
|
||||
} AVRT_PRIORITY, *PAVRT_PRIORITY;
|
||||
typedef enum _AVRT_PRIORITY
|
||||
{
|
||||
AVRT_PRIORITY_LOW = -1,
|
||||
AVRT_PRIORITY_NORMAL,
|
||||
AVRT_PRIORITY_HIGH,
|
||||
AVRT_PRIORITY_CRITICAL
|
||||
} AVRT_PRIORITY, *PAVRT_PRIORITY;
|
||||
#endif
|
||||
|
||||
#include <basetyps.h> // << for IID/CLSID
|
||||
|
|
@ -132,7 +132,7 @@
|
|||
typedef LONGLONG REFERENCE_TIME;
|
||||
#define NONAMELESSUNION
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef WAVE_FORMAT_IEEE_FLOAT
|
||||
#define WAVE_FORMAT_IEEE_FLOAT 0x0003 // 32-bit floating-point
|
||||
#endif
|
||||
|
|
@ -363,10 +363,10 @@ PaWasapiDeviceInfo;
|
|||
typedef struct
|
||||
{
|
||||
PaUtilHostApiRepresentation inheritedHostApiRep;
|
||||
PaUtilStreamInterface callbackStreamInterface;
|
||||
PaUtilStreamInterface blockingStreamInterface;
|
||||
PaUtilStreamInterface callbackStreamInterface;
|
||||
PaUtilStreamInterface blockingStreamInterface;
|
||||
|
||||
PaUtilAllocationGroup *allocations;
|
||||
PaUtilAllocationGroup *allocations;
|
||||
|
||||
/* implementation specific data goes here */
|
||||
|
||||
|
|
@ -450,22 +450,22 @@ typedef struct PaWasapiStream
|
|||
{
|
||||
/* IMPLEMENT ME: rename this */
|
||||
PaUtilStreamRepresentation streamRepresentation;
|
||||
PaUtilCpuLoadMeasurer cpuLoadMeasurer;
|
||||
PaUtilBufferProcessor bufferProcessor;
|
||||
PaUtilCpuLoadMeasurer cpuLoadMeasurer;
|
||||
PaUtilBufferProcessor bufferProcessor;
|
||||
|
||||
// input
|
||||
PaWasapiSubStream in;
|
||||
PaWasapiSubStream in;
|
||||
IAudioCaptureClient *captureClientParent;
|
||||
IStream *captureClientStream;
|
||||
IAudioCaptureClient *captureClient;
|
||||
IAudioEndpointVolume *inVol;
|
||||
IAudioEndpointVolume *inVol;
|
||||
|
||||
// output
|
||||
PaWasapiSubStream out;
|
||||
PaWasapiSubStream out;
|
||||
IAudioRenderClient *renderClientParent;
|
||||
IStream *renderClientStream;
|
||||
IAudioRenderClient *renderClient;
|
||||
IAudioEndpointVolume *outVol;
|
||||
IAudioEndpointVolume *outVol;
|
||||
|
||||
// event handles for event-driven processing mode
|
||||
HANDLE event[S_COUNT];
|
||||
|
|
@ -731,7 +731,7 @@ UINT32 ALIGN_NEXT_POW2(UINT32 v)
|
|||
// Aligns WASAPI buffer to 128 byte packet boundary. HD Audio will fail to play if buffer
|
||||
// is misaligned. This problem was solved in Windows 7 were AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED
|
||||
// is thrown although we must align for Vista anyway.
|
||||
static UINT32 AlignFramesPerBuffer(UINT32 nFrames, UINT32 nSamplesPerSec, UINT32 nBlockAlign,
|
||||
static UINT32 AlignFramesPerBuffer(UINT32 nFrames, UINT32 nSamplesPerSec, UINT32 nBlockAlign,
|
||||
ALIGN_FUNC pAlignFunc)
|
||||
{
|
||||
#define HDA_PACKET_SIZE (128)
|
||||
|
|
@ -751,7 +751,7 @@ static UINT32 AlignFramesPerBuffer(UINT32 nFrames, UINT32 nSamplesPerSec, UINT32
|
|||
|
||||
frame_bytes = packets * HDA_PACKET_SIZE;
|
||||
nFrames = frame_bytes / nBlockAlign;
|
||||
|
||||
|
||||
return nFrames;
|
||||
|
||||
#undef HDA_PACKET_SIZE
|
||||
|
|
@ -1034,7 +1034,7 @@ static MixMonoToStereoF _GetMonoToStereoMixer(PaSampleFormat format, EMixerDir d
|
|||
case paInt24: return _MixMonoToStereo_2TO1_24_L;
|
||||
case paInt32: return _MixMonoToStereo_2TO1_32_L;
|
||||
case paFloat32: return _MixMonoToStereo_2TO1_32f_L;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1061,7 +1061,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
|
|||
If COM is already initialized CoInitialize will either return
|
||||
FALSE, or RPC_E_CHANGED_MODE if it was initialised in a different
|
||||
threading mode. In either case we shouldn't consider it an error
|
||||
but we need to be careful to not call CoUninitialize() if
|
||||
but we need to be careful to not call CoUninitialize() if
|
||||
RPC_E_CHANGED_MODE was returned.
|
||||
*/
|
||||
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
|
|
@ -1102,7 +1102,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
|
|||
paWasapi->enumerator = NULL;
|
||||
hr = CoCreateInstance(&pa_CLSID_IMMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER,
|
||||
&pa_IID_IMMDeviceEnumerator, (void **)&paWasapi->enumerator);
|
||||
|
||||
|
||||
// We need to set the result to a value otherwise we will return paNoError
|
||||
// [IF_FAILED_JUMP(hResult, error);]
|
||||
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
||||
|
|
@ -1118,7 +1118,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
|
|||
// We need to set the result to a value otherwise we will return paNoError
|
||||
// [IF_FAILED_JUMP(hResult, error);]
|
||||
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1142,7 +1142,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
|
|||
// We need to set the result to a value otherwise we will return paNoError
|
||||
// [IF_FAILED_JUMP(hResult, error);]
|
||||
IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1466,7 +1466,7 @@ static void Terminate( PaUtilHostApiRepresentation *hostApi )
|
|||
DWORD calling_thread_id = GetCurrentThreadId();
|
||||
if (g_WasapiInitThread != calling_thread_id)
|
||||
{
|
||||
PRINT(("WASAPI: failed CoUninitializes calling thread[%d] does not match initializing thread[%d]\n",
|
||||
PRINT(("WASAPI: failed CoUninitializes calling thread[%d] does not match initializing thread[%d]\n",
|
||||
calling_thread_id, g_WasapiInitThread));
|
||||
}
|
||||
else
|
||||
|
|
@ -1572,20 +1572,20 @@ static void LogWAVEFORMATEXTENSIBLE(const WAVEFORMATEXTENSIBLE *in)
|
|||
{
|
||||
case WAVE_FORMAT_EXTENSIBLE: {
|
||||
|
||||
PRINT(("wFormatTag =WAVE_FORMAT_EXTENSIBLE\n"));
|
||||
PRINT(("wFormatTag=WAVE_FORMAT_EXTENSIBLE\n"));
|
||||
|
||||
if (IsEqualGUID(&in->SubFormat, &pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
|
||||
{
|
||||
PRINT(("SubFormat =KSDATAFORMAT_SUBTYPE_IEEE_FLOAT\n"));
|
||||
PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_IEEE_FLOAT\n"));
|
||||
}
|
||||
else
|
||||
if (IsEqualGUID(&in->SubFormat, &pa_KSDATAFORMAT_SUBTYPE_PCM))
|
||||
{
|
||||
PRINT(("SubFormat =KSDATAFORMAT_SUBTYPE_PCM\n"));
|
||||
PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_PCM\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT(("SubFormat =CUSTOM GUID{%d:%d:%d:%d%d%d%d%d%d%d%d}\n",
|
||||
PRINT(("SubFormat=CUSTOM GUID{%d:%d:%d:%d%d%d%d%d%d%d%d}\n",
|
||||
in->SubFormat.Data1,
|
||||
in->SubFormat.Data2,
|
||||
in->SubFormat.Data3,
|
||||
|
|
@ -1598,13 +1598,13 @@ static void LogWAVEFORMATEXTENSIBLE(const WAVEFORMATEXTENSIBLE *in)
|
|||
(int)in->SubFormat.Data4[6],
|
||||
(int)in->SubFormat.Data4[7]));
|
||||
}
|
||||
PRINT(("Samples.wValidBitsPerSample =%d\n", in->Samples.wValidBitsPerSample));
|
||||
PRINT(("Samples.wValidBitsPerSample=%d\n", in->Samples.wValidBitsPerSample));
|
||||
PRINT(("dwChannelMask =0x%X\n",in->dwChannelMask));
|
||||
|
||||
break; }
|
||||
|
||||
case WAVE_FORMAT_PCM: PRINT(("wFormatTag =WAVE_FORMAT_PCM\n")); break;
|
||||
case WAVE_FORMAT_IEEE_FLOAT: PRINT(("wFormatTag =WAVE_FORMAT_IEEE_FLOAT\n")); break;
|
||||
case WAVE_FORMAT_PCM: PRINT(("wFormatTag=WAVE_FORMAT_PCM\n")); break;
|
||||
case WAVE_FORMAT_IEEE_FLOAT: PRINT(("wFormatTag=WAVE_FORMAT_IEEE_FLOAT\n")); break;
|
||||
default:
|
||||
PRINT(("wFormatTag =UNKNOWN(%d)\n",old->wFormatTag)); break;
|
||||
}
|
||||
|
|
@ -1642,8 +1642,8 @@ static PaSampleFormat WaveToPaFormat(const WAVEFORMATEXTENSIBLE *in)
|
|||
}
|
||||
}
|
||||
break; }
|
||||
|
||||
case WAVE_FORMAT_IEEE_FLOAT:
|
||||
|
||||
case WAVE_FORMAT_IEEE_FLOAT:
|
||||
return paFloat32;
|
||||
|
||||
case WAVE_FORMAT_PCM: {
|
||||
|
|
@ -1689,13 +1689,13 @@ static PaError MakeWaveFormatFromParams(WAVEFORMATEXTENSIBLE *wavex, const PaStr
|
|||
old->nBlockAlign = (old->nChannels * (old->wBitsPerSample/8));
|
||||
old->nAvgBytesPerSec = (old->nSamplesPerSec * old->nBlockAlign);
|
||||
|
||||
// WAVEFORMATEX
|
||||
//WAVEFORMATEX
|
||||
if ((params->channelCount <= 2) && ((bitsPerSample == 16) || (bitsPerSample == 8)))
|
||||
{
|
||||
old->cbSize = 0;
|
||||
old->wFormatTag = WAVE_FORMAT_PCM;
|
||||
}
|
||||
// WAVEFORMATEXTENSIBLE
|
||||
//WAVEFORMATEXTENSIBLE
|
||||
else
|
||||
{
|
||||
old->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||
|
|
@ -1894,7 +1894,7 @@ static PaError GetClosestFormat(IAudioClient *myClient, double sampleRate,
|
|||
|
||||
// Try selecting suitable sample type
|
||||
for (i = 0; i < STATIC_ARRAY_SIZE(BestToWorst); ++i)
|
||||
{
|
||||
{
|
||||
WAVEFORMATEXTENSIBLE sample = { 0 };
|
||||
|
||||
PaStreamParameters sample_params = stereo_params;
|
||||
|
|
@ -1904,7 +1904,7 @@ static PaError GetClosestFormat(IAudioClient *myClient, double sampleRate,
|
|||
|
||||
hr = IAudioClient_IsFormatSupported(myClient, shareMode, &sample.Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));
|
||||
if (hr == S_OK)
|
||||
{
|
||||
{
|
||||
memcpy(outWavex, &sample, sizeof(WAVEFORMATEXTENSIBLE));
|
||||
CoTaskMemFree(sharedClosestMatch);
|
||||
return (answer = paFormatIsSupported);
|
||||
|
|
@ -1923,14 +1923,14 @@ static PaError GetClosestFormat(IAudioClient *myClient, double sampleRate,
|
|||
MakeWaveFormatFromParams(&spfmt, &spfmt_params, sampleRate);
|
||||
|
||||
hr = IAudioClient_IsFormatSupported(myClient, shareMode, &spfmt.Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL));
|
||||
if (hr == S_OK)
|
||||
{
|
||||
if (hr == S_OK)
|
||||
{
|
||||
memcpy(outWavex, &spfmt, sizeof(WAVEFORMATEXTENSIBLE));
|
||||
CoTaskMemFree(sharedClosestMatch);
|
||||
answer = paFormatIsSupported;
|
||||
answer = paFormatIsSupported;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing helped
|
||||
LogHostError(hr);
|
||||
|
|
@ -2107,11 +2107,11 @@ static void _RecalculateBuffersCount(PaWasapiSubStream *sub, UINT32 userFramesPe
|
|||
// - For Shared mode we use double buffering.
|
||||
if ((sub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) || fullDuplex)
|
||||
{
|
||||
// Exclusive mode does not allow >1 buffers be used for Event interface, e.g. GetBuffer
|
||||
// Exclusive mode does not allow >1 buffers be used for Event interface, e.g. GetBuffer
|
||||
// call must acquire max buffer size and it all must be processed.
|
||||
if (sub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)
|
||||
sub->userBufferAndHostMatch = 1;
|
||||
|
||||
|
||||
// Use paUtilBoundedHostBufferSize because exclusive mode will starve and produce
|
||||
// bad quality of audio
|
||||
sub->buffers = 1;
|
||||
|
|
@ -2119,7 +2119,7 @@ static void _RecalculateBuffersCount(PaWasapiSubStream *sub, UINT32 userFramesPe
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
static void _CalculateAlignedPeriod(PaWasapiSubStream *pSub, UINT32 *nFramesPerLatency,
|
||||
static void _CalculateAlignedPeriod(PaWasapiSubStream *pSub, UINT32 *nFramesPerLatency,
|
||||
ALIGN_FUNC pAlignFunc)
|
||||
{
|
||||
// Align frames to HD Audio packet size of 128 bytes for Exclusive mode only.
|
||||
|
|
@ -2199,10 +2199,10 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
|
|||
framesPerLatency += MakeFramesFromHns(SecondsTonano100(params->suggestedLatency), pSub->wavex.Format.nSamplesPerSec);
|
||||
#else
|
||||
// Calculate host buffer size
|
||||
if ((pSub->shareMode != AUDCLNT_SHAREMODE_EXCLUSIVE) &&
|
||||
if ((pSub->shareMode != AUDCLNT_SHAREMODE_EXCLUSIVE) &&
|
||||
(!pSub->streamFlags || ((pSub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0)))
|
||||
{
|
||||
framesPerLatency = PaUtil_GetFramesPerHostBuffer(userFramesPerBuffer,
|
||||
framesPerLatency = PaUtil_GetFramesPerHostBuffer(userFramesPerBuffer,
|
||||
params->suggestedLatency, pSub->wavex.Format.nSamplesPerSec, 0/*,
|
||||
(pSub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK ? 0 : 1)*/);
|
||||
}
|
||||
|
|
@ -2212,13 +2212,13 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
|
|||
|
||||
// Work 1:1 with user buffer (only polling allows to use >1)
|
||||
framesPerLatency += MakeFramesFromHns(SecondsTonano100(params->suggestedLatency), pSub->wavex.Format.nSamplesPerSec);
|
||||
|
||||
|
||||
// Use Polling if overall latency is > 5ms as it allows to use 100% CPU in a callback,
|
||||
// or user specified latency parameter
|
||||
overall = MakeHnsPeriod(framesPerLatency, pSub->wavex.Format.nSamplesPerSec);
|
||||
if ((overall >= (106667*2)/*21.33ms*/) || ((INT32)(params->suggestedLatency*100000.0) != 0/*0.01 msec granularity*/))
|
||||
{
|
||||
framesPerLatency = PaUtil_GetFramesPerHostBuffer(userFramesPerBuffer,
|
||||
framesPerLatency = PaUtil_GetFramesPerHostBuffer(userFramesPerBuffer,
|
||||
params->suggestedLatency, pSub->wavex.Format.nSamplesPerSec, 0/*,
|
||||
(streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK ? 0 : 1)*/);
|
||||
|
||||
|
|
@ -2258,7 +2258,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
|
|||
// Recalculate aligned period
|
||||
framesPerLatency = MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec);
|
||||
_CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_BWD);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2268,7 +2268,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
|
|||
// Recalculate aligned period
|
||||
framesPerLatency = MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec);
|
||||
_CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_FWD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! Windows 7 does not allow to set latency lower than minimal device period and will
|
||||
|
|
@ -2277,8 +2277,8 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
|
|||
*/
|
||||
{
|
||||
/*! AUDCLNT_E_BUFFER_SIZE_ERROR: Applies to Windows 7 and later.
|
||||
Indicates that the buffer duration value requested by an exclusive-mode client is
|
||||
out of range. The requested duration value for pull mode must not be greater than
|
||||
Indicates that the buffer duration value requested by an exclusive-mode client is
|
||||
out of range. The requested duration value for pull mode must not be greater than
|
||||
500 milliseconds; for push mode the duration value must not be greater than 2 seconds.
|
||||
*/
|
||||
if (pSub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)
|
||||
|
|
@ -2319,7 +2319,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
|
|||
NULL);
|
||||
|
||||
/*! WASAPI is tricky on large device buffer, sometimes 2000ms can be allocated sometimes
|
||||
less. There is no known guaranteed level thus we make subsequent tries by decreasing
|
||||
less. There is no known guaranteed level thus we make subsequent tries by decreasing
|
||||
buffer by 100ms per try.
|
||||
*/
|
||||
while ((hr == E_OUTOFMEMORY) && (pSub->period > (100 * 10000)))
|
||||
|
|
@ -2469,9 +2469,9 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu
|
|||
IAudioClient_AddRef(pSub->clientParent);
|
||||
|
||||
// Recalculate buffers count
|
||||
_RecalculateBuffersCount(pSub,
|
||||
userFramesPerBuffer,
|
||||
MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec),
|
||||
_RecalculateBuffersCount(pSub,
|
||||
userFramesPerBuffer,
|
||||
MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec),
|
||||
fullDuplex);
|
||||
|
||||
done:
|
||||
|
|
@ -2766,7 +2766,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||
|
||||
// Only get IAudioCaptureClient input once here instead of getting it at multiple places based on the use
|
||||
hr = IAudioClient_GetService(stream->in.clientParent, &pa_IID_IAudioCaptureClient, (void **)&stream->captureClientParent);
|
||||
if (hr != S_OK)
|
||||
if (hr != S_OK)
|
||||
{
|
||||
LogHostError(hr);
|
||||
LogPaError(result = paUnanticipatedHostError);
|
||||
|
|
@ -2782,10 +2782,10 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||
|
||||
// buffer
|
||||
if ((stream->in.tailBuffer = PaUtil_AllocateMemory(sizeof(PaUtilRingBuffer))) == NULL)
|
||||
{
|
||||
{
|
||||
LogPaError(result = paInsufficientMemory);
|
||||
goto error;
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
memset(stream->in.tailBuffer, 0, sizeof(PaUtilRingBuffer));
|
||||
|
||||
// buffer memory region
|
||||
|
|
@ -2801,7 +2801,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||
{
|
||||
LogPaError(result = paInternalError);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -2873,10 +2873,10 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||
goto error;
|
||||
}
|
||||
|
||||
// Get closest format
|
||||
// Get closest format
|
||||
hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( WaveToPaFormat(&stream->out.wavex), outputSampleFormat );
|
||||
|
||||
// Set user-side custom host processor
|
||||
// Set user-side custom host processor
|
||||
if ((outputStreamInfo != NULL) &&
|
||||
(outputStreamInfo->flags & paWinWasapiRedirectHostProcessor))
|
||||
{
|
||||
|
|
@ -2886,13 +2886,13 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||
|
||||
// Only get IAudioCaptureClient output once here instead of getting it at multiple places based on the use
|
||||
hr = IAudioClient_GetService(stream->out.clientParent, &pa_IID_IAudioRenderClient, (void **)&stream->renderClientParent);
|
||||
if (hr != S_OK)
|
||||
if (hr != S_OK)
|
||||
{
|
||||
LogHostError(hr);
|
||||
LogPaError(result = paUnanticipatedHostError);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
outputChannelCount = 0;
|
||||
|
|
@ -2974,7 +2974,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||
else
|
||||
if (outputParameters)
|
||||
{
|
||||
if ((stream->out.buffers == 1) &&
|
||||
if ((stream->out.buffers == 1) &&
|
||||
(!stream->out.streamFlags || ((stream->out.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0)))
|
||||
bufferMode = paUtilBoundedHostBufferSize;
|
||||
}
|
||||
|
|
@ -3263,30 +3263,30 @@ static PaError StartStream( PaStream *s )
|
|||
if ((stream->in.clientParent && (stream->in.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)) ||
|
||||
(stream->out.clientParent && (stream->out.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)))
|
||||
{
|
||||
if ((stream->hThread = CREATE_THREAD(ProcThreadEvent)) == NULL)
|
||||
if ((stream->hThread = CREATE_THREAD(ProcThreadEvent)) == NULL)
|
||||
{
|
||||
PRINT(("Failed creating thread: ProcThreadEvent."));
|
||||
result = paUnanticipatedHostError;
|
||||
goto nonblocking_start_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((stream->hThread = CREATE_THREAD(ProcThreadPoll)) == NULL)
|
||||
if ((stream->hThread = CREATE_THREAD(ProcThreadPoll)) == NULL)
|
||||
{
|
||||
PRINT(("Failed creating thread: ProcThreadPoll."));
|
||||
result = paUnanticipatedHostError;
|
||||
goto nonblocking_start_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for thread to start
|
||||
if (WaitForSingleObject(stream->hThreadStart, 60*1000) == WAIT_TIMEOUT)
|
||||
if (WaitForSingleObject(stream->hThreadStart, 60*1000) == WAIT_TIMEOUT)
|
||||
{
|
||||
PRINT(("Failed starting thread: timeout."));
|
||||
result = paUnanticipatedHostError;
|
||||
goto nonblocking_start_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -3300,7 +3300,7 @@ static PaError StartStream( PaStream *s )
|
|||
}
|
||||
}
|
||||
if (stream->in.clientParent != NULL)
|
||||
{
|
||||
{
|
||||
if ((stream->hBlockingOpStreamRD = CreateEvent(NULL, TRUE, TRUE, NULL)) == NULL)
|
||||
{
|
||||
result = paInsufficientMemory;
|
||||
|
|
@ -3506,7 +3506,7 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames )
|
|||
}
|
||||
|
||||
if (buf2 != NULL)
|
||||
{
|
||||
{
|
||||
// Register available frames to processor
|
||||
PaUtil_SetInputFrameCount(&stream->bufferProcessor, buf2_size);
|
||||
|
||||
|
|
@ -3525,9 +3525,9 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames )
|
|||
// Read hardware
|
||||
while (frames != 0)
|
||||
{
|
||||
// Check if blocking call must be interrupted
|
||||
// Check if blocking call must be interrupted
|
||||
if (WaitForSingleObject(stream->hCloseRequest, sleep) != WAIT_TIMEOUT)
|
||||
break;
|
||||
break;
|
||||
|
||||
// Get available frames (must be finding out available frames before call to IAudioCaptureClient_GetBuffer
|
||||
// othervise audio glitches will occur inExclusive mode as it seems that WASAPI has some scheduling/
|
||||
|
|
@ -3536,7 +3536,7 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames )
|
|||
{
|
||||
LogHostError(hr);
|
||||
return paUnanticipatedHostError;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for more frames to become available
|
||||
if (available == 0)
|
||||
|
|
@ -3558,7 +3558,7 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames )
|
|||
// Avoid busy waiting, schedule next 1 millesecond wait
|
||||
if (sleep == 0)
|
||||
sleep = ThreadIdleScheduler_NextSleep(&sched);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((sleep = ThreadIdleScheduler_NextSleep(&sched)) != 0)
|
||||
|
|
@ -3586,10 +3586,10 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames )
|
|||
|
||||
// Register available frames to processor
|
||||
PaUtil_SetInputFrameCount(&stream->bufferProcessor, available);
|
||||
|
||||
|
||||
// Register host buffer pointer to processor
|
||||
PaUtil_SetInterleavedInputChannels(&stream->bufferProcessor, 0, wasapi_buffer, stream->bufferProcessor.inputChannelCount);
|
||||
|
||||
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);
|
||||
frames -= processed;
|
||||
|
|
@ -3658,18 +3658,18 @@ static PaError WriteStream( PaStream* s, const void *_buffer, unsigned long fram
|
|||
}
|
||||
|
||||
// Blocking (potentially, untill 'frames' are consumed) loop
|
||||
while (frames != 0)
|
||||
{
|
||||
// Check if blocking call must be interrupted
|
||||
while (frames != 0)
|
||||
{
|
||||
// Check if blocking call must be interrupted
|
||||
if (WaitForSingleObject(stream->hCloseRequest, sleep) != WAIT_TIMEOUT)
|
||||
break;
|
||||
break;
|
||||
|
||||
// Get frames available
|
||||
if ((hr = _PollGetOutputFramesAvailable(stream, &available)) != S_OK)
|
||||
{
|
||||
LogHostError(hr);
|
||||
{
|
||||
LogHostError(hr);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for more frames to become available
|
||||
if (available == 0)
|
||||
|
|
@ -3688,42 +3688,42 @@ static PaError WriteStream( PaStream* s, const void *_buffer, unsigned long fram
|
|||
|
||||
// Keep in 'frmaes' range
|
||||
if (available > frames)
|
||||
available = frames;
|
||||
available = frames;
|
||||
|
||||
// Get pointer to host buffer
|
||||
// Get pointer to host buffer
|
||||
if ((hr = IAudioRenderClient_GetBuffer(stream->renderClient, available, &wasapi_buffer)) != S_OK)
|
||||
{
|
||||
// Buffer size is too big, waiting
|
||||
if (hr == AUDCLNT_E_BUFFER_TOO_LARGE)
|
||||
continue;
|
||||
{
|
||||
// Buffer size is too big, waiting
|
||||
if (hr == AUDCLNT_E_BUFFER_TOO_LARGE)
|
||||
continue;
|
||||
|
||||
LogHostError(hr);
|
||||
LogHostError(hr);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep waiting again (on Vista it was noticed that WASAPI could SOMETIMES return NULL pointer
|
||||
// to buffer without returning AUDCLNT_E_BUFFER_TOO_LARGE instead)
|
||||
if (wasapi_buffer == NULL)
|
||||
continue;
|
||||
|
||||
// Register available frames to processor
|
||||
PaUtil_SetOutputFrameCount(&stream->bufferProcessor, available);
|
||||
|
||||
// Register host buffer pointer to processor
|
||||
PaUtil_SetInterleavedOutputChannels(&stream->bufferProcessor, 0, wasapi_buffer, stream->bufferProcessor.outputChannelCount);
|
||||
|
||||
// Register available frames to processor
|
||||
PaUtil_SetOutputFrameCount(&stream->bufferProcessor, available);
|
||||
|
||||
// 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), this call will advance
|
||||
// pointer 'user_buffer' to consumed portion of data
|
||||
processed = PaUtil_CopyOutput(&stream->bufferProcessor, (const void **)&user_buffer, frames);
|
||||
frames -= processed;
|
||||
|
||||
// Release host buffer
|
||||
// Release host buffer
|
||||
if ((hr = IAudioRenderClient_ReleaseBuffer(stream->renderClient, available, 0)) != S_OK)
|
||||
{
|
||||
LogHostError(hr);
|
||||
{
|
||||
LogHostError(hr);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
|
|
@ -4631,7 +4631,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
|
|||
DWORD sleep_ms = 0;
|
||||
DWORD sleep_ms_in;
|
||||
DWORD sleep_ms_out;
|
||||
|
||||
|
||||
BOOL bThreadComInitialized = FALSE;
|
||||
|
||||
/*
|
||||
|
|
@ -4675,7 +4675,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
|
|||
sleep_ms_out = GetFramesSleepTime(stream->bufferProcessor.framesPerUserBuffer, stream->out.wavex.Format.nSamplesPerSec);
|
||||
}
|
||||
|
||||
// Choose smallest
|
||||
// Choose smallest
|
||||
if ((sleep_ms_in != 0) && (sleep_ms_out != 0))
|
||||
sleep_ms = min(sleep_ms_in, sleep_ms_out);
|
||||
else
|
||||
|
|
@ -4715,14 +4715,14 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
|
|||
{
|
||||
if ((hr = IAudioClient_Start(stream->in.clientProc)) != S_OK)
|
||||
{
|
||||
LogHostError(hr);
|
||||
goto thread_error;
|
||||
LogHostError(hr);
|
||||
goto thread_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize event & start OUTPUT stream
|
||||
if (stream->out.clientProc)
|
||||
{
|
||||
{
|
||||
// Preload buffer (obligatory, othervise ->Start() will fail), avoid processing
|
||||
// when in full-duplex mode as it requires input processing as well
|
||||
if (!PA_WASAPI__IS_FULLDUPLEX(stream))
|
||||
|
|
@ -4739,22 +4739,22 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
|
|||
if ((hr = ProcessOutputBuffer(stream, processor, frames)) != S_OK)
|
||||
{
|
||||
LogHostError(hr); // not fatal, just log
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
if (frames != 0)
|
||||
{
|
||||
{
|
||||
if ((hr = ProcessOutputBuffer(stream, processor, frames)) != S_OK)
|
||||
{
|
||||
{
|
||||
LogHostError(hr); // not fatal, just log
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
LogHostError(hr); // not fatal, just log
|
||||
}
|
||||
}
|
||||
|
|
@ -4817,7 +4817,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
|
|||
LogHostError(hr);
|
||||
goto thread_error;
|
||||
}
|
||||
|
||||
|
||||
// output
|
||||
if (stream->bufferMode == paUtilFixedHostBufferSize)
|
||||
{
|
||||
|
|
@ -4827,7 +4827,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
|
|||
{
|
||||
LogHostError(hr);
|
||||
goto thread_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -4838,7 +4838,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
|
|||
{
|
||||
LogHostError(hr);
|
||||
goto thread_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4908,7 +4908,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
|
|||
|
||||
LogPaError(paInsufficientMemory);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// replace buffer pointer
|
||||
|
|
@ -4981,7 +4981,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param)
|
|||
if (sleep_ms == 0)
|
||||
{
|
||||
next_sleep = ThreadIdleScheduler_NextSleep(&scheduler);
|
||||
}
|
||||
}
|
||||
|
||||
// get available frames
|
||||
if ((hr = _PollGetOutputFramesAvailable(stream, &o_frames)) != S_OK)
|
||||
|
|
|
|||
Loading…
Reference in a new issue