ASIO:
- Certain drivers write over the available memory of PaAsioDriverInfo, now a padding area makes sure the stack doesn't get corrupted. WDM-KS: - Corrected capture event handling
This commit is contained in:
parent
f5bb9cfec0
commit
32e0080310
2 changed files with 58 additions and 47 deletions
|
|
@ -1031,8 +1031,6 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
|
|||
PaAsioHostApiRepresentation *asioHostApi;
|
||||
PaAsioDeviceInfo *deviceInfoArray;
|
||||
char **names;
|
||||
PaAsioDriverInfo paAsioDriverInfo;
|
||||
|
||||
asioHostApi = (PaAsioHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaAsioHostApiRepresentation) );
|
||||
if( !asioHostApi )
|
||||
{
|
||||
|
|
@ -1142,6 +1140,13 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
|
|||
|
||||
for( i=0; i < driverCount; ++i )
|
||||
{
|
||||
/* Due to the headless design of the ASIO API, drivers are free to write over data given to them (like M-Audio
|
||||
drivers f.i.). This is an attempt to overcome that. */
|
||||
union _tag_local {
|
||||
PaAsioDriverInfo info;
|
||||
char _padding[4096];
|
||||
} paAsioDriver;
|
||||
|
||||
|
||||
PA_DEBUG(("ASIO names[%d]:%s\n",i,names[i]));
|
||||
|
||||
|
|
@ -1176,7 +1181,7 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
|
|||
|
||||
|
||||
/* Attempt to load the asio driver... */
|
||||
if( LoadAsioDriver( asioHostApi, names[i], &paAsioDriverInfo, asioHostApi->systemSpecific ) == paNoError )
|
||||
if( LoadAsioDriver( asioHostApi, names[i], &paAsioDriver.info, asioHostApi->systemSpecific ) == paNoError )
|
||||
{
|
||||
PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
|
||||
PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo;
|
||||
|
|
@ -1186,15 +1191,15 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
|
|||
|
||||
deviceInfo->name = names[i];
|
||||
PA_DEBUG(("PaAsio_Initialize: drv:%d name = %s\n", i,deviceInfo->name));
|
||||
PA_DEBUG(("PaAsio_Initialize: drv:%d inputChannels = %d\n", i, paAsioDriverInfo.inputChannelCount));
|
||||
PA_DEBUG(("PaAsio_Initialize: drv:%d outputChannels = %d\n", i, paAsioDriverInfo.outputChannelCount));
|
||||
PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMinSize = %d\n", i, paAsioDriverInfo.bufferMinSize));
|
||||
PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMaxSize = %d\n", i, paAsioDriverInfo.bufferMaxSize));
|
||||
PA_DEBUG(("PaAsio_Initialize: drv:%d bufferPreferredSize = %d\n", i, paAsioDriverInfo.bufferPreferredSize));
|
||||
PA_DEBUG(("PaAsio_Initialize: drv:%d bufferGranularity = %d\n", i, paAsioDriverInfo.bufferGranularity));
|
||||
PA_DEBUG(("PaAsio_Initialize: drv:%d inputChannels = %d\n", i, paAsioDriver.info.inputChannelCount));
|
||||
PA_DEBUG(("PaAsio_Initialize: drv:%d outputChannels = %d\n", i, paAsioDriver.info.outputChannelCount));
|
||||
PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMinSize = %d\n", i, paAsioDriver.info.bufferMinSize));
|
||||
PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMaxSize = %d\n", i, paAsioDriver.info.bufferMaxSize));
|
||||
PA_DEBUG(("PaAsio_Initialize: drv:%d bufferPreferredSize = %d\n", i, paAsioDriver.info.bufferPreferredSize));
|
||||
PA_DEBUG(("PaAsio_Initialize: drv:%d bufferGranularity = %d\n", i, paAsioDriver.info.bufferGranularity));
|
||||
|
||||
deviceInfo->maxInputChannels = paAsioDriverInfo.inputChannelCount;
|
||||
deviceInfo->maxOutputChannels = paAsioDriverInfo.outputChannelCount;
|
||||
deviceInfo->maxInputChannels = paAsioDriver.info.inputChannelCount;
|
||||
deviceInfo->maxOutputChannels = paAsioDriver.info.outputChannelCount;
|
||||
|
||||
deviceInfo->defaultSampleRate = 0.;
|
||||
bool foundDefaultSampleRate = false;
|
||||
|
|
@ -1222,13 +1227,13 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
|
|||
*/
|
||||
|
||||
double defaultLowLatency =
|
||||
paAsioDriverInfo.bufferPreferredSize / deviceInfo->defaultSampleRate;
|
||||
paAsioDriver.info.bufferPreferredSize / deviceInfo->defaultSampleRate;
|
||||
|
||||
deviceInfo->defaultLowInputLatency = defaultLowLatency;
|
||||
deviceInfo->defaultLowOutputLatency = defaultLowLatency;
|
||||
|
||||
double defaultHighLatency =
|
||||
paAsioDriverInfo.bufferMaxSize / deviceInfo->defaultSampleRate;
|
||||
paAsioDriver.info.bufferMaxSize / deviceInfo->defaultSampleRate;
|
||||
|
||||
if( defaultHighLatency < defaultLowLatency )
|
||||
defaultHighLatency = defaultLowLatency; /* just in case the driver returns something strange */
|
||||
|
|
@ -1249,10 +1254,10 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
|
|||
PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighInputLatency = %f\n", i, deviceInfo->defaultHighInputLatency));
|
||||
PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighOutputLatency = %f\n", i, deviceInfo->defaultHighOutputLatency));
|
||||
|
||||
asioDeviceInfo->minBufferSize = paAsioDriverInfo.bufferMinSize;
|
||||
asioDeviceInfo->maxBufferSize = paAsioDriverInfo.bufferMaxSize;
|
||||
asioDeviceInfo->preferredBufferSize = paAsioDriverInfo.bufferPreferredSize;
|
||||
asioDeviceInfo->bufferGranularity = paAsioDriverInfo.bufferGranularity;
|
||||
asioDeviceInfo->minBufferSize = paAsioDriver.info.bufferMinSize;
|
||||
asioDeviceInfo->maxBufferSize = paAsioDriver.info.bufferMaxSize;
|
||||
asioDeviceInfo->preferredBufferSize = paAsioDriver.info.bufferPreferredSize;
|
||||
asioDeviceInfo->bufferGranularity = paAsioDriver.info.bufferGranularity;
|
||||
|
||||
|
||||
asioDeviceInfo->asioChannelInfos = (ASIOChannelInfo*)PaUtil_GroupAllocateMemory(
|
||||
|
|
|
|||
|
|
@ -1532,6 +1532,8 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa
|
|||
|
||||
{
|
||||
ULONG topoPinId = GetConnectedPin(pinId, (pin->dataFlow == KSPIN_DATAFLOW_IN), parentFilter, -1, NULL, NULL);
|
||||
const wchar_t kInputName[] = L"Input";
|
||||
const wchar_t kOutputName[] = L"Output";
|
||||
|
||||
if (topoPinId != KSFILTER_NODE)
|
||||
{
|
||||
|
|
@ -1580,7 +1582,7 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa
|
|||
/* Make sure pin gets a name here... */
|
||||
if (wcslen(pin->friendlyName) == 0)
|
||||
{
|
||||
wcscpy(pin->friendlyName, (pin->dataFlow == KSPIN_DATAFLOW_IN) ? L"Output" : L"Input");
|
||||
wcscpy(pin->friendlyName, (pin->dataFlow == KSPIN_DATAFLOW_IN) ? kOutputName : kInputName);
|
||||
#ifdef UNICODE
|
||||
PA_DEBUG(("PinNew: Setting pin friendly name to '%s'\n", pin->friendlyName));
|
||||
#else
|
||||
|
|
@ -1798,7 +1800,7 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa
|
|||
/* Make sure we get a name for the pin */
|
||||
if (wcslen(pin->friendlyName) == 0)
|
||||
{
|
||||
wcscpy(pin->friendlyName, L"Input");
|
||||
wcscpy(pin->friendlyName, kInputName);
|
||||
}
|
||||
#ifdef UNICODE
|
||||
PA_DEBUG(("PinNew: Input friendly name '%s'\n", pin->friendlyName));
|
||||
|
|
@ -1875,7 +1877,8 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa
|
|||
result = GetNameFromCategory(&category, TRUE, pin->inputs[i]->friendlyName, MAX_PATH);
|
||||
if (result != paNoError)
|
||||
{
|
||||
_snwprintf(pin->inputs[i]->friendlyName, MAX_PATH, L"Input %d", i + 1);
|
||||
/* Only specify name, let name hash in ScanDeviceInfos fix postfix enumerators */
|
||||
wcscpy(pin->inputs[i]->friendlyName, kInputName);
|
||||
}
|
||||
}
|
||||
#ifdef UNICODE
|
||||
|
|
@ -1903,14 +1906,7 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa
|
|||
{
|
||||
PA_DEBUG(("PinNew: No topology pin id found. Bad...\n"));
|
||||
/* No TOPO pin id ??? This is bad. Ok, so we just say it is an input or output... */
|
||||
if (pin->dataFlow == KSPIN_DATAFLOW_IN)
|
||||
{
|
||||
wcscpy(pin->friendlyName, L"Line Out");
|
||||
}
|
||||
else
|
||||
{
|
||||
wcscpy(pin->friendlyName, L"Line In");
|
||||
}
|
||||
wcscpy(pin->friendlyName, (pin->dataFlow == KSPIN_DATAFLOW_IN) ? kOutputName : kInputName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5422,8 +5418,6 @@ static PaError PreparePinsForStart(PaProcessThreadInfo* pInfo)
|
|||
{
|
||||
goto error;
|
||||
}
|
||||
/* Reset the events as some devices SET the event on PinRead */
|
||||
ResetEvent(pInfo->stream->capture.packets[i].Signal.hEvent);
|
||||
++pInfo->pending;
|
||||
}
|
||||
}
|
||||
|
|
@ -5903,24 +5897,27 @@ PA_THREAD_FUNC ProcessingThread(void* pParam)
|
|||
{
|
||||
if (eventSignalled < captureEvents)
|
||||
{
|
||||
timeStamp[0] = dwCurrentTime;
|
||||
info.stream->capture.pPin->fnEventHandler(&info, eventSignalled);
|
||||
/* Since we use the ring buffer, we can submit the buffers directly */
|
||||
if (!info.stream->streamStop)
|
||||
if (info.stream->capture.pPin->fnEventHandler(&info, eventSignalled) == paNoError)
|
||||
{
|
||||
result = info.stream->capture.pPin->fnSubmitHandler(&info, info.captureTail);
|
||||
if (result != paNoError)
|
||||
timeStamp[0] = dwCurrentTime;
|
||||
|
||||
/* Since we use the ring buffer, we can submit the buffers directly */
|
||||
if (!info.stream->streamStop)
|
||||
{
|
||||
PA_HP_TRACE((info.stream->hLog, "Capture submit handler failed with result %d", result));
|
||||
break;
|
||||
result = info.stream->capture.pPin->fnSubmitHandler(&info, info.captureTail);
|
||||
if (result != paNoError)
|
||||
{
|
||||
PA_HP_TRACE((info.stream->hLog, "Capture submit handler failed with result %d", result));
|
||||
break;
|
||||
}
|
||||
}
|
||||
++info.captureTail;
|
||||
/* If full-duplex, let _only_ render event trigger processing. We still need the stream stop
|
||||
handling working, so let that be processed anyways... */
|
||||
if (info.stream->userOutputChannels > 0)
|
||||
{
|
||||
doProcessing = 0;
|
||||
}
|
||||
}
|
||||
++info.captureTail;
|
||||
/* If full-duplex, let _only_ render event trigger processing. We still need the stream stop
|
||||
handling working, so let that be processed anyways... */
|
||||
if (info.stream->userOutputChannels > 0)
|
||||
{
|
||||
doProcessing = 0;
|
||||
}
|
||||
}
|
||||
else if (eventSignalled < renderEvents)
|
||||
|
|
@ -6317,6 +6314,16 @@ static PaError PaPinCaptureEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, u
|
|||
|
||||
assert( eventIndex < pInfo->stream->capture.noOfPackets );
|
||||
|
||||
if (packet->Header.DataUsed == 0)
|
||||
{
|
||||
PA_HP_TRACE((pInfo->stream->hLog, ">>> Capture bogus event: idx=%u (DataUsed=%u)", eventIndex, packet->Header.DataUsed));
|
||||
|
||||
/* Bogus event, reset! This is to handle the behavior of this USB mic: http://shop.xtz.se/measurement-system/microphone-to-dirac-live-room-correction-suite
|
||||
on startup of streaming, where it erroneously sets the event without the corresponding buffer being filled (DataUsed == 0) */
|
||||
ResetEvent(packet->Signal.hEvent);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pInfo->capturePackets[pInfo->captureHead & cPacketsArrayMask].packet = packet;
|
||||
|
||||
frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer, packet->Header.Data, pInfo->stream->capture.framesPerBuffer);
|
||||
|
|
@ -6335,9 +6342,8 @@ static PaError PaPinCaptureSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo,
|
|||
assert(packet != 0);
|
||||
PA_HP_TRACE((pInfo->stream->hLog, "Capture submit: %u", eventIndex));
|
||||
packet->Header.DataUsed = 0; /* Reset for reuse */
|
||||
result = PinRead(pInfo->stream->capture.pPin->handle, packet);
|
||||
/* Reset event, as some drivers might not do so (or even set the event!!), resulting in a 100% CPU capture loop */
|
||||
ResetEvent(packet->Signal.hEvent);
|
||||
result = PinRead(pInfo->stream->capture.pPin->handle, packet);
|
||||
++pInfo->pending;
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue