]> Repos - portaudio/commitdiff
ASIO:
authorrobiwan <robiwan@0f58301d-fd10-0410-b4af-bbb618454e57>
Thu, 23 Feb 2012 15:29:24 +0000 (15:29 +0000)
committerrobiwan <robiwan@0f58301d-fd10-0410-b4af-bbb618454e57>
Thu, 23 Feb 2012 15:29:24 +0000 (15:29 +0000)
- 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

src/hostapi/asio/pa_asio.cpp
src/hostapi/wdmks/pa_win_wdmks.c

index 2f90c288502bf4de39cff48622eb3498212b394a..5735e160f1a3682279002719fa1fedb032ddc07a 100644 (file)
@@ -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(
index 515e7903b21410a09b90059551e6c26762790c6d..ba5ae5518e1d522d6fb9bf13352196637152eb0f 100644 (file)
@@ -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;
 }