#define PRINT(x) PA_DEBUG(x);\r
\r
#define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \\r
- PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )\r
+ PaUtil_SetLastHostErrorInfo( paWASAPI, errorCode, errorText )\r
\r
#ifndef IF_FAILED_JUMP\r
#define IF_FAILED_JUMP(hr, label) if(FAILED(hr)) goto label;\r
WCHAR defaultRenderer [MAX_STR_LEN];\r
WCHAR defaultCapturer [MAX_STR_LEN];\r
\r
- PaWasapiDeviceInfo *devInfo;\r
+ PaWasapiDeviceInfo *devInfo;\r
+\r
+ // Is true when WOW64 Vista Workaround is needed\r
+ bool useVistaWOW64Workaround;\r
}\r
PaWasapiHostApiRepresentation;\r
\r
IAudioClient *client;\r
WAVEFORMATEXTENSIBLE wavex;\r
UINT32 bufferSize;\r
- REFERENCE_TIME latency;\r
+ REFERENCE_TIME device_latency;\r
REFERENCE_TIME period;\r
double latency_seconds;\r
UINT32 framesPerHostCallback;\r
{\r
#define HDA_PACKET_SIZE 128\r
\r
- long packets_total = nSamplesPerSec * nBlockAlign / HDA_PACKET_SIZE;\r
+ long packets_total = 10000 * (nSamplesPerSec * nBlockAlign / HDA_PACKET_SIZE);\r
long frame_bytes = nFrames * nBlockAlign;\r
\r
// align to packet size\r
hDInputDLL = NULL;\r
}\r
\r
+// ------------------------------------------------------------------------------------------\r
+static BOOL IsWow64()\r
+{\r
+ // http://msdn.microsoft.com/en-us/library/ms684139(VS.85).aspx\r
+\r
+ typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);\r
+ LPFN_ISWOW64PROCESS fnIsWow64Process;\r
+\r
+ BOOL bIsWow64 = FALSE;\r
+\r
+ // IsWow64Process is not available on all supported versions of Windows.\r
+ // Use GetModuleHandle to get a handle to the DLL that contains the function\r
+ // and GetProcAddress to get a pointer to the function if available.\r
+\r
+ fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(\r
+ GetModuleHandle(TEXT("kernel32")), TEXT("IsWow64Process"));\r
+\r
+ if (fnIsWow64Process == NULL)\r
+ return FALSE;\r
+\r
+ if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))\r
+ return FALSE;\r
+\r
+ return bIsWow64;\r
+}\r
+\r
+// ------------------------------------------------------------------------------------------\r
+typedef enum EWindowsVersion\r
+{\r
+ WINDOWS_UNKNOWN,\r
+ WINDOWS_VISTA_SERVER2008,\r
+ WINDOWS_7_SERVER2008R2\r
+}\r
+EWindowsVersion;\r
+// The function is limited to Vista/7 mostly as we need just to find out Vista/WOW64 combination\r
+// in order to use WASAPI WOW64 workarounds.\r
+static EWindowsVersion GetWindowsVersion()\r
+{\r
+ DWORD dwVersion = 0; \r
+ DWORD dwMajorVersion = 0;\r
+ DWORD dwMinorVersion = 0; \r
+ DWORD dwBuild = 0;\r
+\r
+ typedef DWORD (WINAPI *LPFN_GETVERSION)(VOID);\r
+ LPFN_GETVERSION fnGetVersion;\r
+\r
+ fnGetVersion = (LPFN_GETVERSION) GetProcAddress(\r
+ GetModuleHandle(TEXT("kernel32")), TEXT("GetVersion"));\r
+ \r
+ if (fnGetVersion == NULL)\r
+ return WINDOWS_UNKNOWN;\r
+\r
+ dwVersion = fnGetVersion();\r
+ \r
+ // Get the Windows version\r
+ dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));\r
+ dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));\r
+\r
+ // Get the build number\r
+ if (dwVersion < 0x80000000) \r
+ dwBuild = (DWORD)(HIWORD(dwVersion));\r
+\r
+ switch (dwMajorVersion)\r
+ {\r
+ case 6: \r
+ switch (dwMinorVersion)\r
+ {\r
+ case 0:\r
+ return WINDOWS_VISTA_SERVER2008;\r
+ case 1:\r
+ return WINDOWS_7_SERVER2008R2;\r
+ }\r
+ }\r
+\r
+ return WINDOWS_UNKNOWN;\r
+}\r
+\r
+// ------------------------------------------------------------------------------------------\r
+static bool UseWOW64VistaWorkaround()\r
+{\r
+ return (::IsWow64() && (::GetWindowsVersion() == WINDOWS_VISTA_SERVER2008));\r
+}\r
+\r
// ------------------------------------------------------------------------------------------\r
PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )\r
{\r
GetStreamTime, PaUtil_DummyGetCpuLoad,\r
ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );\r
\r
+\r
+ // findout if platform workaround is required\r
+ paWasapi->useVistaWOW64Workaround = ::UseWOW64VistaWorkaround();\r
+\r
SAFE_RELEASE(pEndPoints);\r
\r
return result;\r
const PaStreamParameters *outputParameters,\r
double sampleRate)\r
{\r
- if (inputParameters != NULL)\r
+ if (hostApi == NULL)\r
+ return paHostApiNotFound;\r
+ \r
+ if (inputParameters != NULL)\r
{\r
/* all standard sample formats are supported by the buffer adapter,\r
this implementation doesn't support any custom sample formats */\r
\r
// ------------------------------------------------------------------------------------------\r
static HRESULT CreateAudioClient(PaWasapiSubStream *pSubStream, PaWasapiDeviceInfo *info,\r
- const PaStreamParameters *params, UINT32 framesPerBuffer, double sampleRate, UINT32 streamFlags, \r
+ const PaStreamParameters *params, UINT32 framesPerLatency, double sampleRate, UINT32 streamFlags, \r
PaError *pa_error)\r
{\r
if (!pSubStream || !info || !params)\r
return E_POINTER;\r
- if ((sampleRate == 0) || (framesPerBuffer == 0))\r
+ if ((UINT32)sampleRate == 0)\r
return E_INVALIDARG;\r
\r
PaError error;\r
return AUDCLNT_E_UNSUPPORTED_FORMAT;\r
}\r
\r
- // Align frames\r
- framesPerBuffer = AlignFramesPerBuffer(framesPerBuffer, \r
- pSubStream->wavex.Format.nSamplesPerSec, pSubStream->wavex.Format.nBlockAlign);\r
+ // Add latency frames\r
+ framesPerLatency += MakeFramesFromHns(SecondsTonano100(params->suggestedLatency), pSubStream->wavex.Format.nSamplesPerSec);\r
+\r
+ // Align frames to HD Audio packet size of 128 bytes for Exclusive mode only.\r
+ // Not aligning on Windows Vista will cause Event timeout, although Windows 7 will\r
+ // return AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED error to realign buffer. Aligning is necessary\r
+ // for Exclusive mode only! when audio data is feeded directly to hardware.\r
+ if (pSubStream->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)\r
+ {\r
+ framesPerLatency = AlignFramesPerBuffer(framesPerLatency, \r
+ pSubStream->wavex.Format.nSamplesPerSec, pSubStream->wavex.Format.nBlockAlign);\r
+ }\r
\r
// Calculate period\r
- pSubStream->period = MakeHnsPeriod(framesPerBuffer, pSubStream->wavex.Format.nSamplesPerSec);\r
- pSubStream->period += ::SecondsTonano100(params->suggestedLatency);\r
+ pSubStream->period = MakeHnsPeriod(framesPerLatency, pSubStream->wavex.Format.nSamplesPerSec);\r
\r
- // Let's do not enforce min, it is even a bug as MinimumDevicePeriod will make buffer not aligned\r
- // on Vista\r
- //pSubStream->period = (pSubStream->period < info->MinimumDevicePeriod ? info->MinimumDevicePeriod : pSubStream->period);\r
+ // Enforce min/max period for device in Shared mode to avoid distorted sound.\r
+ // Avoid doing so for Exclusive mode as alignment will suffer. Exclusive mode processes\r
+ // big buffers without problem. Push Exclusive beyond limits if possible.\r
+ if (pSubStream->shareMode == AUDCLNT_SHAREMODE_SHARED)\r
+ {\r
+ if (pSubStream->period < info->DefaultDevicePeriod)\r
+ pSubStream->period = info->DefaultDevicePeriod;\r
+ }\r
\r
- // Open the stream and associate it with an audio session\r
+ // Open the stream and associate it with an audio session\r
hr = pAudioClient->Initialize( \r
pSubStream->shareMode,\r
streamFlags/*AUDCLNT_STREAMFLAGS_EVENTCALLBACK*/, \r
goto done;\r
}\r
\r
- // Get the next aligned frame\r
- hr = pAudioClient->GetBufferSize(&nFrames);\r
- if (hr != S_OK)\r
- {\r
- LogHostError(hr);\r
- goto done;\r
- }\r
- \r
// Set result\r
pSubStream->client = pAudioClient;\r
pSubStream->client->AddRef();\r
PaSampleFormat inputSampleFormat, outputSampleFormat;\r
PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;\r
PaWasapiStreamInfo *inputStreamInfo = NULL, *outputStreamInfo = NULL;\r
+ PaWasapiDeviceInfo *info = NULL;\r
\r
// validate PaStreamParameters\r
if ((result = IsStreamParamsValid(hostApi, inputParameters, outputParameters, sampleRate)) != paNoError)\r
// Default thread priority is Audio: for exclusive mode we will use Pro Audio.\r
stream->nThreadPriority = eThreadPriorityAudio;\r
\r
+ // Set default number of frames: paFramesPerBufferUnspecified\r
+ if (framesPerBuffer == paFramesPerBufferUnspecified)\r
+ { \r
+ UINT32 framesPerBufferIn = 0, framesPerBufferOut = 0;\r
+ if (inputParameters != NULL)\r
+ {\r
+ info = &paWasapi->devInfo[inputParameters->device];\r
+ framesPerBufferIn = MakeFramesFromHns(info->DefaultDevicePeriod, (UINT32)sampleRate);\r
+ }\r
+ if (outputParameters != NULL)\r
+ {\r
+ info = &paWasapi->devInfo[outputParameters->device];\r
+ framesPerBufferOut = MakeFramesFromHns(info->DefaultDevicePeriod, (UINT32)sampleRate);\r
+ }\r
+ // choosing maximum default size\r
+ framesPerBuffer = max(framesPerBufferIn, framesPerBufferOut);\r
+ }\r
+\r
// Try create device: Input\r
if (inputParameters != NULL)\r
{\r
inputChannelCount = inputParameters->channelCount;\r
inputSampleFormat = inputParameters->sampleFormat;\r
inputStreamInfo = (PaWasapiStreamInfo *)inputParameters->hostApiSpecificStreamInfo;\r
- PaWasapiDeviceInfo *info = &paWasapi->devInfo[inputParameters->device];\r
+ info = &paWasapi->devInfo[inputParameters->device];\r
stream->in.flags = (inputStreamInfo ? inputStreamInfo->flags : 0);\r
\r
// Select Exclusive/Shared mode\r
\r
// Choose processing mode\r
stream->in.streamFlags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;\r
+ if (paWasapi->useVistaWOW64Workaround)\r
+ stream->in.streamFlags = 0; // polling interface\r
if (streamCallback == NULL)\r
stream->in.streamFlags = 0; // polling interface\r
if ((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiPolling))\r
stream->in.streamFlags = 0; // polling interface\r
\r
// Create Audio client\r
- HRESULT hr = CreateAudioClient(&stream->in, info, inputParameters, framesPerBuffer, \r
+ HRESULT hr = CreateAudioClient(&stream->in, info, inputParameters, 0/*framesPerLatency*/, \r
sampleRate, stream->in.streamFlags, &result);\r
if (hr != S_OK)\r
{\r
}\r
LogWAVEFORMATEXTENSIBLE(&stream->in.wavex);\r
\r
+ // Get closest format\r
+ hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->in.wavex), inputSampleFormat );\r
+\r
// Create volume mgr\r
stream->inVol = NULL;\r
/*hResult = info->device->Activate(\r
if (hr != S_OK)\r
{\r
LogHostError(hr);\r
- return paInvalidDevice;\r
+ LogPaError(result = paInvalidDevice);\r
+ goto error;\r
}\r
\r
// Correct buffer to max size if it maxed out result of GetBufferSize\r
- stream->in.bufferSize = (framesPerBuffer > maxBufferSize ? maxBufferSize : framesPerBuffer);\r
+ stream->in.bufferSize = maxBufferSize;\r
\r
- // Get stream latency\r
- hr = stream->in.client->GetStreamLatency(&stream->in.latency);\r
+ // Get interface latency (actually uneeded as we calculate latency from the size\r
+ // of maxBufferSize).\r
+ hr = stream->in.client->GetStreamLatency(&stream->in.device_latency);\r
if (hr != S_OK)\r
{\r
LogHostError(hr);\r
- return paInvalidDevice;\r
+ LogPaError(result = paInvalidDevice);\r
+ goto error;\r
}\r
- stream->in.latency_seconds = nano100ToSeconds(stream->in.latency);\r
+ //stream->in.latency_seconds = nano100ToSeconds(stream->in.device_latency);\r
\r
- // Number of samples that are required at each period\r
- stream->in.framesPerHostCallback = \r
- (stream->in.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? maxBufferSize : stream->in.bufferSize);\r
+ // Number of frames that are required at each period\r
+ stream->in.framesPerHostCallback = maxBufferSize;\r
\r
- // Get closest format\r
- hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->in.wavex), inputSampleFormat );\r
+ // Calculate buffer latency\r
+ PaTime buffer_latency = (PaTime)maxBufferSize / stream->in.wavex.Format.nSamplesPerSec;\r
+\r
+ // Append buffer latency to interface latency in shared mode (see GetStreamLatency notes)\r
+ stream->in.latency_seconds += buffer_latency;\r
\r
- UINT32 latency = (1000 * maxBufferSize) / stream->in.wavex.Format.nSamplesPerSec + (UINT32)nano100ToMillis(stream->in.latency);\r
- PRINT(("PaWASAPIOpenStream: (input) framesPerHostCallback: %d\n", (UINT32)stream->in.framesPerHostCallback));\r
- PRINT(("PaWASAPIOpenStream: (input) latency: %d\n", stream->in.latency));\r
+ PRINT(("PaWASAPIOpenStream(input): framesPerHostCallback[ %d ] latency[ %.02fms ]\n", (UINT32)stream->in.framesPerHostCallback, (float)(stream->in.latency_seconds*1000.0f)));\r
}\r
else\r
{\r
outputChannelCount = outputParameters->channelCount;\r
outputSampleFormat = outputParameters->sampleFormat;\r
outputStreamInfo = (PaWasapiStreamInfo *)outputParameters->hostApiSpecificStreamInfo;\r
- PaWasapiDeviceInfo *info = &paWasapi->devInfo[outputParameters->device];\r
+ info = &paWasapi->devInfo[outputParameters->device];\r
stream->out.flags = (outputStreamInfo ? outputStreamInfo->flags : 0);\r
\r
// Select Exclusive/Shared mode\r
\r
// Choose processing mode\r
stream->out.streamFlags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;\r
+ if (paWasapi->useVistaWOW64Workaround)\r
+ stream->out.streamFlags = 0; // polling interface\r
if (streamCallback == NULL)\r
stream->out.streamFlags = 0; // polling interface\r
if ((outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiPolling))\r
stream->out.streamFlags = 0; // polling interface\r
\r
// Create Audio client\r
- HRESULT hr = CreateAudioClient(&stream->out, info, outputParameters, framesPerBuffer, \r
+ HRESULT hr = CreateAudioClient(&stream->out, info, outputParameters, 0/*framesPerLatency*/, \r
sampleRate, stream->out.streamFlags, &result);\r
if (hr != S_OK)\r
{\r
}\r
LogWAVEFORMATEXTENSIBLE(&stream->out.wavex);\r
\r
+ // Get closest format\r
+ hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->out.wavex), outputSampleFormat );\r
+\r
// Activate volume\r
stream->outVol = NULL;\r
/*hResult = info->device->Activate(\r
}\r
\r
// Correct buffer to max size if it maxed out result of GetBufferSize\r
- stream->out.bufferSize = (framesPerBuffer > maxBufferSize ? maxBufferSize : framesPerBuffer);\r
+ stream->out.bufferSize = maxBufferSize;\r
\r
- // Get stream latency\r
- hr = stream->out.client->GetStreamLatency(&stream->out.latency);\r
+ // Get interface latency (actually uneeded as we calculate latency from the size\r
+ // of maxBufferSize).\r
+ hr = stream->out.client->GetStreamLatency(&stream->out.device_latency);\r
if (hr != S_OK)\r
{\r
LogHostError(hr);\r
LogPaError(result = paInvalidDevice);\r
goto error;\r
}\r
- stream->out.latency_seconds = nano100ToSeconds(stream->out.latency);\r
+ //stream->out.latency_seconds = nano100ToSeconds(stream->out.device_latency);\r
\r
- // Number of samples that are required at each period\r
- stream->out.framesPerHostCallback = \r
- (stream->out.shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE ? maxBufferSize : stream->out.bufferSize);\r
+ // Number of frames that are required at each period\r
+ stream->out.framesPerHostCallback = maxBufferSize;\r
\r
- // Get closest format\r
- hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( waveformatToPaFormat(&stream->out.wavex), outputSampleFormat );\r
+ // Calculate buffer latency\r
+ PaTime buffer_latency = (PaTime)maxBufferSize / stream->out.wavex.Format.nSamplesPerSec;\r
\r
- UINT32 latency = (1000 * maxBufferSize) / stream->out.wavex.Format.nSamplesPerSec + (UINT32)nano100ToMillis(stream->out.latency);\r
- PRINT(("PaWASAPIOpenStream: (output) framesPerHostCallback: %d\n", (UINT32)stream->out.framesPerHostCallback));\r
- PRINT(("PaWASAPIOpenStream: (output) latency: %d\n", latency));\r
- }\r
+ // Append buffer latency to interface latency in shared mode (see GetStreamLatency notes)\r
+ stream->out.latency_seconds += buffer_latency;\r
+\r
+ PRINT(("PaWASAPIOpenStream(output): framesPerHostCallback[ %d ] latency[ %.02fms ]\n", (UINT32)stream->out.framesPerHostCallback, (float)(stream->out.latency_seconds*1000.0f)));\r
+ }\r
else\r
{\r
outputChannelCount = 0;\r
}\r
}\r
\r
+ // Initialize stream representation\r
if (streamCallback)\r
{\r
stream->bBlocking = false;\r
PaUtil_InitializeStreamRepresentation(&stream->streamRepresentation,\r
- &paWasapi->callbackStreamInterface, streamCallback, userData);\r
+ &paWasapi->callbackStreamInterface, \r
+ streamCallback, userData);\r
}\r
else\r
{\r
stream->bBlocking = true;\r
PaUtil_InitializeStreamRepresentation(&stream->streamRepresentation,\r
- &paWasapi->blockingStreamInterface, streamCallback, userData);\r
+ &paWasapi->blockingStreamInterface, \r
+ streamCallback, userData);\r
}\r
\r
+ // Initialize CPU measurer\r
PaUtil_InitializeCpuLoadMeasurer(&stream->cpuLoadMeasurer, sampleRate);\r
\r
if (outputParameters && inputParameters)\r
ULONG framesPerHostCallback = (outputParameters) ? stream->out.framesPerHostCallback:\r
stream->in.framesPerHostCallback;\r
\r
- /* we assume a fixed host buffer size in this example, but the buffer processor\r
- can also support bounded and unknown host buffer sizes by passing\r
- paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of\r
- paUtilFixedHostBufferSize below.\r
- */\r
- result = PaUtil_InitializeBufferProcessor(&stream->bufferProcessor,\r
- inputChannelCount, inputSampleFormat, hostInputSampleFormat,\r
- outputChannelCount, outputSampleFormat, hostOutputSampleFormat,\r
- sampleRate, streamFlags, framesPerBuffer,\r
- framesPerHostCallback, paUtilFixedHostBufferSize,\r
- streamCallback, userData);\r
+ // Choose correct mode of buffer processing:\r
+ // Exclusive/Shared non paWinWasapiPolling mode: paUtilFixedHostBufferSize - always fixed\r
+ // Exclusive/Shared paWinWasapiPolling mode: paUtilBoundedHostBufferSize - may vary\r
+ PaUtilHostBufferSizeMode bufferMode = paUtilFixedHostBufferSize;\r
+ if (inputParameters && \r
+ (!stream->in.streamFlags || ((stream->in.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0)))\r
+ bufferMode = paUtilBoundedHostBufferSize;\r
+ else\r
+ if (outputParameters && \r
+ (!stream->out.streamFlags || ((stream->out.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0)))\r
+ bufferMode = paUtilBoundedHostBufferSize;\r
+\r
+ // Initialize buffer processor\r
+ result = PaUtil_InitializeBufferProcessor(\r
+ &stream->bufferProcessor,\r
+ inputChannelCount, \r
+ inputSampleFormat, \r
+ hostInputSampleFormat,\r
+ outputChannelCount, \r
+ outputSampleFormat, \r
+ hostOutputSampleFormat,\r
+ sampleRate, \r
+ streamFlags, \r
+ framesPerBuffer,\r
+ framesPerHostCallback, \r
+ bufferMode,\r
+ streamCallback, \r
+ userData);\r
if (result != paNoError)\r
{\r
LogPaError(result);\r
PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)\r
+ ((outputParameters)?stream->out.latency_seconds :0);\r
\r
+ // Set SR\r
stream->streamRepresentation.streamInfo.sampleRate = sampleRate;\r
\r
(*s) = (PaStream *)stream;\r
-\r
return result;\r
\r
error:\r
\r
if (stream)\r
+ {\r
+ CloseStream(stream);\r
PaUtil_FreeMemory(stream);\r
+ }\r
\r
return result;\r
}\r
PaError result = paNoError;\r
PaWasapiStream *stream = (PaWasapiStream*)s;\r
\r
+ // validate\r
+ if (s == NULL)\r
+ return paBadStreamPtr;\r
+\r
// abort active stream\r
if (IsStreamActive(s))\r
{\r
HRESULT hr;\r
PaWasapiStream *stream = (PaWasapiStream*)s;\r
\r
+ // validate\r
+ if (s == NULL)\r
+ return paBadStreamPtr;\r
+\r
// check if stream is active already\r
if (IsStreamActive(s))\r
return paStreamIsNotStopped;\r
{\r
PaError result = paNoError;\r
\r
+ // validate\r
+ if (s == NULL)\r
+ return paBadStreamPtr;\r
+\r
// Finish stream\r
_FinishStream((PaWasapiStream *)s);\r
\r
{\r
PaError result = paNoError;\r
\r
+ // validate\r
+ if (s == NULL)\r
+ return paBadStreamPtr;\r
+\r
// Finish stream\r
_FinishStream((PaWasapiStream *)s);\r
\r
static PaTime GetStreamTime( PaStream *s )\r
{\r
PaWasapiStream *stream = (PaWasapiStream*)s;\r
- if (stream == NULL)\r
+ \r
+ // validate\r
+ if (s == NULL)\r
return paBadStreamPtr;\r
\r
/* suppress unused variable warnings */\r
static PaError ReadStream( PaStream* s, void *_buffer, unsigned long _frames )\r
{\r
PaWasapiStream *stream = (PaWasapiStream*)s;\r
- if (stream == NULL)\r
+ \r
+ // validate\r
+ if (s == NULL)\r
return paBadStreamPtr;\r
+ if (_buffer == NULL)\r
+ return paBadBufferPtr;\r
+ if (_frames == 0)\r
+ return paBufferTooSmall;\r
\r
HRESULT hr = S_OK;\r
UINT32 frames;\r
{\r
PaWasapiStream *stream = (PaWasapiStream*)s;\r
\r
- if (stream == NULL)\r
+ // validate\r
+ if (s == NULL)\r
return paBadStreamPtr;\r
+ if (_buffer == NULL)\r
+ return paBadBufferPtr;\r
+ if (_frames == 0)\r
+ return paBufferTooSmall;\r
\r
if (!stream->running)\r
return paStreamIsStopped;\r
{\r
PaWasapiStream *stream = (PaWasapiStream*)s;\r
\r
- if (stream == NULL)\r
+ // validate\r
+ if (s == NULL)\r
return paBadStreamPtr;\r
\r
if (!stream->running)\r
{\r
PaWasapiStream *stream = (PaWasapiStream*)s;\r
\r
- if (stream == NULL)\r
+ // validate\r
+ if (s == NULL)\r
return paBadStreamPtr;\r
\r
if (!stream->running)\r
{\r
PaTime pending_time;\r
if ((hResult = stream->in.client->GetCurrentPadding(&pending)) == S_OK)\r
- pending_time = ((PaTime)pending / (PaTime)stream->in.wavex.Format.nSamplesPerSec) + stream->in.latency_seconds;\r
+ pending_time = (PaTime)pending / (PaTime)stream->in.wavex.Format.nSamplesPerSec;\r
else\r
- pending_time = (PaTime)stream->in.framesPerHostCallback / (PaTime)stream->in.wavex.Format.nSamplesPerSec;\r
+ pending_time = (PaTime)stream->in.latency_seconds;\r
\r
timeInfo.inputBufferAdcTime = timeInfo.currentTime + pending_time;\r
}\r
{\r
PaTime pending_time;\r
if ((hResult = stream->out.client->GetCurrentPadding(&pending)) == S_OK)\r
- pending_time = ((PaTime)pending / (PaTime)stream->out.wavex.Format.nSamplesPerSec) + stream->out.latency_seconds;\r
+ pending_time = (PaTime)pending / (PaTime)stream->out.wavex.Format.nSamplesPerSec;\r
else\r
- pending_time = (PaTime)stream->out.framesPerHostCallback / (PaTime)stream->out.wavex.Format.nSamplesPerSec;\r
+ pending_time = (PaTime)stream->out.latency_seconds;\r
\r
timeInfo.outputBufferDacTime = timeInfo.currentTime + pending_time;\r
}\r
\r
// Get buffer\r
if ((hr = stream->rclient->GetBuffer(frames, &data)) != S_OK)\r
- return LogHostError(hr);\r
+ {\r
+ if (stream->out.shareMode == AUDCLNT_SHAREMODE_SHARED)\r
+ {\r
+ // Using GetCurrentPadding to overcome AUDCLNT_E_BUFFER_TOO_LARGE in\r
+ // shared mode results in no sound in Event-driven mode (MSDN does not\r
+ // document this, or is it WASAPI bug?), thus we better\r
+ // try to acquire buffer next time when GetBuffer allows to do so.\r
+#if 0\r
+ // Get Read position\r
+ UINT32 padding = 0;\r
+ hr = stream->out.client->GetCurrentPadding(&padding);\r
+ if (hr != S_OK)\r
+ return LogHostError(hr);\r
+\r
+ // Get frames to write\r
+ frames -= padding;\r
+ if (frames == 0)\r
+ return S_OK;\r
+\r
+ if ((hr = stream->rclient->GetBuffer(frames, &data)) != S_OK)\r
+ return LogHostError(hr);\r
+#else\r
+ if (hr == AUDCLNT_E_BUFFER_TOO_LARGE)\r
+ return S_OK; // be silent in shared mode, try again next time\r
+#endif\r
+ }\r
+ else\r
+ return LogHostError(hr);\r
+ }\r
\r
// Process data\r
processor[S_OUTPUT].processor(NULL, 0, data, frames, processor[S_OUTPUT].userData);\r
for (;;)\r
{\r
// 2 sec timeout\r
- dwResult = WaitForMultipleObjects(S_COUNT, event, FALSE, 2000);\r
+ dwResult = WaitForMultipleObjects(S_COUNT, event, FALSE, 10000);\r
\r
// Check for close event (after wait for buffers to avoid any calls to user\r
// callback when hCloseRequest was set)\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
- //SetEvent(stream->hCloseRequest);\r
break; }\r
\r
// Input stream\r
break;\r
\r
UINT32 frames = stream->out.framesPerHostCallback;\r
- BYTE *data = NULL;\r
- DWORD flags = 0;\r
\r
// Get Read position\r
UINT32 padding = 0;\r
hr = stream->out.client->GetCurrentPadding(&padding);\r
- if (hr != S_OK || padding == 0)\r
+ if (hr != S_OK)\r
+ {\r
+ LogHostError(hr);\r
break;\r
+ }\r
\r
// Fill buffer\r
frames -= padding;\r