Show
Ignore:
Timestamp:
02/29/08 03:59:47 (9 months ago)
Author:
rossb
Message:

Blocking i/o implementation by Sven Fischer. adds pa_asio dependency on pa_ringbuffer.c. Added i386 memory barriers for MSVC and BORLAND

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • portaudio/branches/v19-devel/src/hostapi/asio/pa_asio.cpp

    r1348 r1363  
    66 * Based on the Open Source API proposed by Ross Bencina 
    77 * Copyright (c) 2000-2002 Stephane Letz, Phil Burk, Ross Bencina 
     8 * Blocking i/o implementation by Sven Fischer, Institute of Hearing 
     9 * Technology and Audiology (www.hoertechnik-audiologie.de) 
    810 * 
    911 * Permission is hereby granted, free of charge, to any person obtaining 
     
    7274 
    7375/** @file 
    74         @ingroup hostapi_src 
     76    @ingroup hostapi_src 
    7577 
    7678    Note that specific support for paInputUnderflow, paOutputOverflow and 
     
    8082    @todo implement host api specific extension to set i/o buffer sizes in frames 
    8183 
    82     @todo implement ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable 
     84    @todo review ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable 
     85 
     86    @todo review Blocking i/o latency computations in OpenStream(), changing ring  
     87          buffer to a non-power-of-two structure could reduce blocking i/o latency. 
    8388 
    8489    @todo implement IsFormatSupported 
     
    132137#include "pa_process.h" 
    133138#include "pa_debugprint.h" 
     139#include "pa_ringbuffer.h" 
    134140 
    135141/* This version of pa_asio.cpp is currently only targetted at Win32, 
     
    213219static signed long GetStreamWriteAvailable( PaStream* stream ); 
    214220 
     221/* Blocking i/o callback function. */ 
     222static int BlockingIoPaCallback(const void                     *inputBuffer    , 
     223                                      void                     *outputBuffer   , 
     224                                      unsigned long             framesPerBuffer, 
     225                                const PaStreamCallbackTimeInfo *timeInfo       , 
     226                                      PaStreamCallbackFlags     statusFlags    , 
     227                                      void                     *userData       ); 
     228 
    215229/* our ASIO callback functions */ 
    216230 
     
    277291// Atomic increment and decrement operations 
    278292#if MAC 
    279         /* need to be implemented on Mac */ 
    280         inline long PaAsio_AtomicIncrement(volatile long* v) {return ++(*const_cast<long*>(v));} 
    281         inline long PaAsio_AtomicDecrement(volatile long* v) {return --(*const_cast<long*>(v));} 
     293    /* need to be implemented on Mac */ 
     294    inline long PaAsio_AtomicIncrement(volatile long* v) {return ++(*const_cast<long*>(v));} 
     295    inline long PaAsio_AtomicDecrement(volatile long* v) {return --(*const_cast<long*>(v));} 
    282296#elif WINDOWS 
    283         inline long PaAsio_AtomicIncrement(volatile long* v) {return InterlockedIncrement(const_cast<long*>(v));} 
    284         inline long PaAsio_AtomicDecrement(volatile long* v) {return InterlockedDecrement(const_cast<long*>(v));} 
     297    inline long PaAsio_AtomicIncrement(volatile long* v) {return InterlockedIncrement(const_cast<long*>(v));} 
     298    inline long PaAsio_AtomicDecrement(volatile long* v) {return InterlockedDecrement(const_cast<long*>(v));} 
    285299#endif 
    286300 
     
    925939 
    926940PaError PaAsio_GetAvailableLatencyValues( PaDeviceIndex device, 
    927                 long *minLatency, long *maxLatency, long *preferredLatency, long *granularity ) 
     941        long *minLatency, long *maxLatency, long *preferredLatency, long *granularity ) 
    928942{ 
    929943    PaError result; 
     
    11311145        } 
    11321146 
    1133                 IsDebuggerPresent_ = GetProcAddress( LoadLibrary( "Kernel32.dll" ), "IsDebuggerPresent" ); 
     1147        IsDebuggerPresent_ = GetProcAddress( LoadLibrary( "Kernel32.dll" ), "IsDebuggerPresent" ); 
    11341148 
    11351149        for( i=0; i < driverCount; ++i ) 
     
    14531467 
    14541468    if( asioHostApi->openAsioDeviceIndex != paNoDevice  
    1455                         && asioHostApi->openAsioDeviceIndex != asioDeviceIndex ) 
     1469            && asioHostApi->openAsioDeviceIndex != asioDeviceIndex ) 
    14561470    { 
    14571471        return paDeviceUnavailable; 
     
    15141528 
    15151529 
     1530/** A data structure specifically for storing blocking i/o related data. */ 
     1531typedef struct PaAsioStreamBlockingState 
     1532{ 
     1533    int stopFlag; /**< Flag indicating that block processing is to be stopped. */ 
     1534 
     1535    unsigned long writeBuffersRequested; /**< The number of available output buffers, requested by the #WriteStream() function. */ 
     1536    unsigned long readFramesRequested;   /**< The number of available input frames, requested by the #ReadStream() function. */ 
     1537 
     1538    int writeBuffersRequestedFlag; /**< Flag to indicate that #WriteStream() has requested more output buffers to be available. */ 
     1539    int readFramesRequestedFlag;   /**< Flag to indicate that #ReadStream() requires more input frames to be available. */ 
     1540 
     1541    HANDLE writeBuffersReadyEvent; /**< Event to signal that requested output buffers are available. */ 
     1542    HANDLE readFramesReadyEvent;   /**< Event to signal that requested input frames are available. */ 
     1543 
     1544    void *writeRingBufferData; /**< The actual ring buffer memory, used by the output ring buffer. */ 
     1545    void *readRingBufferData;  /**< The actual ring buffer memory, used by the input ring buffer. */ 
     1546 
     1547    PaUtilRingBuffer writeRingBuffer; /**< Frame-aligned blocking i/o ring buffer to store output data (interleaved user format). */ 
     1548    PaUtilRingBuffer readRingBuffer;  /**< Frame-aligned blocking i/o ring buffer to store input data (interleaved user format). */ 
     1549 
     1550    long writeRingBufferInitialFrames; /**< The initial number of silent frames within the output ring buffer. */ 
     1551 
     1552    const void **writeStreamBuffer; /**< Temp buffer, used by #WriteStream() for handling non-interleaved data. */ 
     1553    void **readStreamBuffer; /**< Temp buffer, used by #ReadStream() for handling non-interleaved data. */ 
     1554 
     1555    PaUtilBufferProcessor bufferProcessor; /**< Buffer processor, used to handle the blocking i/o ring buffers. */ 
     1556 
     1557    int outputUnderflowFlag; /**< Flag to signal an output underflow from within the callback function. */ 
     1558    int inputOverflowFlag; /**< Flag to signal an input overflow from within the callback function. */ 
     1559} 
     1560PaAsioStreamBlockingState; 
     1561 
     1562 
     1563 
    15161564/* PaAsioStream - a stream data structure specifically for this implementation */ 
    15171565 
     
    15571605 
    15581606    PaStreamCallbackFlags callbackFlags; 
     1607 
     1608    PaAsioStreamBlockingState *blockingState; /**< Blocking i/o data struct, or NULL when using callback interface. */ 
    15591609} 
    15601610PaAsioStream; 
     
    16561706        int **channelSelectors ) 
    16571707{ 
    1658         if( streamInfo ) 
    1659         { 
    1660             if( streamInfo->size != sizeof( PaAsioStreamInfo ) 
    1661                     || streamInfo->version != 1 ) 
    1662             { 
    1663                 return paIncompatibleHostApiSpecificStreamInfo; 
    1664             } 
    1665  
    1666             if( streamInfo->flags & paAsioUseChannelSelectors ) 
     1708    if( streamInfo ) 
     1709    { 
     1710        if( streamInfo->size != sizeof( PaAsioStreamInfo ) 
     1711                || streamInfo->version != 1 ) 
     1712        { 
     1713            return paIncompatibleHostApiSpecificStreamInfo; 
     1714        } 
     1715 
     1716        if( streamInfo->flags & paAsioUseChannelSelectors ) 
    16671717            *channelSelectors = streamInfo->channelSelectors; 
    16681718 
     
    16761726             }            
    16771727        } 
    1678         } 
    1679  
    1680         return paNoError; 
     1728    } 
     1729 
     1730    return paNoError; 
    16811731} 
    16821732 
     
    17151765    bool isExternal = false; 
    17161766 
     1767    /* Are we using blocking i/o interface? */ 
     1768    int usingBlockingIo = ( !streamCallback ) ? TRUE : FALSE; 
     1769    /* Blocking i/o stuff */ 
     1770    long lBlockingBufferSize     = 0; /* Desired ring buffer size in samples. */ 
     1771    long lBlockingBufferSizePow2 = 0; /* Power-of-2 rounded ring buffer size. */ 
     1772    long lBytesPerFrame          = 0; /* Number of bytes per input/output frame. */ 
     1773    int blockingWriteBuffersReadyEventInitialized = 0; /* Event init flag. */ 
     1774    int blockingReadFramesReadyEventInitialized   = 0; /* Event init flag. */ 
     1775 
     1776    int callbackBufferProcessorInited = FALSE; 
     1777    int blockingBufferProcessorInited = FALSE; 
     1778 
    17171779    /* unless we move to using lower level ASIO calls, we can only have 
    17181780        one device open at a time */ 
     
    17311793            PA_DEBUG(("OpenStream paBadIODeviceCombination\n")); 
    17321794            return paBadIODeviceCombination; 
    1733     } 
     1795        } 
    17341796    } 
    17351797 
     
    19211983        goto error; 
    19221984    } 
     1985    stream->blockingState = NULL; /* Blocking i/o not initialized, yet. */ 
     1986 
    19231987 
    19241988    stream->completedBuffersPlayedEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); 
     
    19372001    stream->bufferPtrs = 0; /* for deallocation in error */ 
    19382002 
    1939     if( streamCallback ) 
     2003    /* Using blocking i/o interface... */ 
     2004    if( usingBlockingIo ) 
     2005    { 
     2006        /* Blocking i/o is implemented by running callback mode, using a special blocking i/o callback. */ 
     2007        streamCallback = BlockingIoPaCallback; /* Setup PA to use the ASIO blocking i/o callback. */ 
     2008        userData       = &theAsioStream;       /* The callback user data will be the PA ASIO stream. */ 
     2009        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, 
     2010                                               &asioHostApi->blockingStreamInterface, streamCallback, userData ); 
     2011    } 
     2012    else /* Using callback interface... */ 
    19402013    { 
    19412014        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, 
    19422015                                               &asioHostApi->callbackStreamInterface, streamCallback, userData ); 
    1943     } 
    1944     else 
    1945     { 
    1946         PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, 
    1947                                                &asioHostApi->blockingStreamInterface, streamCallback, userData ); 
    19482016    } 
    19492017 
     
    19962064 
    19972065 
    1998     framesPerHostBuffer = SelectHostBufferSize( 
    1999             (( suggestedInputLatencyFrames > suggestedOutputLatencyFrames ) 
    2000                     ? suggestedInputLatencyFrames : suggestedOutputLatencyFrames), 
    2001             driverInfo ); 
    2002  
    2003  
    2004         PA_DEBUG(("PaAsioOpenStream: framesPerHostBuffer :%d\n",  framesPerHostBuffer)); 
     2066    /* Using blocking i/o interface... */ 
     2067    if( usingBlockingIo ) 
     2068    { 
     2069/** @todo REVIEW selection of host buffer size for blocking i/o */ 
     2070        /* Use default host latency for blocking i/o. */ 
     2071        framesPerHostBuffer = SelectHostBufferSize( 0, driverInfo ); 
     2072 
     2073    } 
     2074    else /* Using callback interface... */ 
     2075    { 
     2076        framesPerHostBuffer = SelectHostBufferSize( 
     2077                (( suggestedInputLatencyFrames > suggestedOutputLatencyFrames ) 
     2078                        ? suggestedInputLatencyFrames : suggestedOutputLatencyFrames), 
     2079                driverInfo ); 
     2080    } 
     2081 
     2082 
     2083    PA_DEBUG(("PaAsioOpenStream: framesPerHostBuffer :%d\n",  framesPerHostBuffer)); 
    20052084 
    20062085    asioError = ASIOCreateBuffers( stream->asioBufferInfos, 
     
    21402219    } 
    21412220 
    2142     result =  PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, 
    2143                     inputChannelCount, inputSampleFormat, hostInputSampleFormat, 
    2144                     outputChannelCount, outputSampleFormat, hostOutputSampleFormat, 
    2145                     sampleRate, streamFlags, framesPerBuffer, 
    2146                     framesPerHostBuffer, paUtilFixedHostBufferSize, 
    2147                     streamCallback, userData ); 
    2148     if( result != paNoError ){ 
    2149         PA_DEBUG(("OpenStream ERROR13\n")); 
    2150         goto error; 
    2151     } 
    2152  
    21532221 
    21542222    ASIOGetLatencies( &stream->inputLatency, &stream->outputLatency ); 
    21552223 
    2156     stream->streamRepresentation.streamInfo.inputLatency = 
    2157             (double)( PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor) 
    2158                 + stream->inputLatency) / sampleRate;   // seconds 
    2159     stream->streamRepresentation.streamInfo.outputLatency = 
    2160             (double)( PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor) 
    2161                 + stream->outputLatency) / sampleRate; // seconds 
    2162     stream->streamRepresentation.streamInfo.sampleRate = sampleRate; 
    2163  
    2164     // the code below prints the ASIO latency which doesn't include the 
    2165     // buffer processor latency. it reports the added latency separately 
    2166     PA_DEBUG(("PaAsio : ASIO InputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n", 
    2167             stream->inputLatency, 
    2168             (long)((stream->inputLatency*1000)/ sampleRate),   
    2169             PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor), 
    2170             (long)((PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)*1000)/ sampleRate) 
    2171             )); 
    2172  
    2173     PA_DEBUG(("PaAsio : ASIO OuputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n", 
    2174             stream->outputLatency, 
    2175             (long)((stream->outputLatency*1000)/ sampleRate),  
    2176             PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor), 
    2177             (long)((PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)*1000)/ sampleRate) 
    2178             )); 
     2224 
     2225    /* Using blocking i/o interface... */ 
     2226    if( usingBlockingIo ) 
     2227    { 
     2228        /* Allocate the blocking i/o input ring buffer memory. */ 
     2229        stream->blockingState = (PaAsioStreamBlockingState*)PaUtil_AllocateMemory( sizeof(PaAsioStreamBlockingState) ); 
     2230        if( !stream->blockingState ) 
     2231        { 
     2232            result = paInsufficientMemory; 
     2233            PA_DEBUG(("ERROR! Blocking i/o interface struct allocation failed in OpenStream()\n")); 
     2234            goto error; 
     2235        } 
     2236 
     2237        /* Initialize blocking i/o interface struct. */ 
     2238        stream->blockingState->readFramesReadyEvent   = NULL; /* Uninitialized, yet. */ 
     2239        stream->blockingState->writeBuffersReadyEvent = NULL; /* Uninitialized, yet. */ 
     2240        stream->blockingState->readRingBufferData     = NULL; /* Uninitialized, yet. */ 
     2241        stream->blockingState->writeRingBufferData    = NULL; /* Uninitialized, yet. */ 
     2242        stream->blockingState->readStreamBuffer       = NULL; /* Uninitialized, yet. */ 
     2243        stream->blockingState->writeStreamBuffer      = NULL; /* Uninitialized, yet. */ 
     2244        stream->blockingState->stopFlag               = TRUE; /* Not started, yet. */ 
     2245 
     2246 
     2247        /* If the user buffer is unspecified */ 
     2248        if( framesPerBuffer == paFramesPerBufferUnspecified ) 
     2249        { 
     2250            /* Make the user buffer the same size as the host buffer. */ 
     2251            framesPerBuffer = framesPerHostBuffer; 
     2252        } 
     2253 
     2254 
     2255        /* Initialize callback buffer processor. */ 
     2256        result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor               , 
     2257                                                    inputChannelCount                     , 
     2258                                                    inputSampleFormat & ~paNonInterleaved , /* Ring buffer. */ 
     2259                                                    hostInputSampleFormat                 , /* Host format. */ 
     2260                                                    outputChannelCount                    , 
     2261                                                    outputSampleFormat & ~paNonInterleaved, /* Ring buffer. */ 
     2262                                                    hostOutputSampleFormat                , /* Host format. */ 
     2263                                                    sampleRate                            , 
     2264                                                    streamFlags                           , 
     2265                                                    framesPerBuffer                       , /* Frames per ring buffer block. */ 
     2266                                                    framesPerHostBuffer                   , /* Frames per asio buffer. */ 
     2267                                                    paUtilFixedHostBufferSize             , 
     2268                                                    streamCallback                        , 
     2269                                                    userData                               ); 
     2270        if( result != paNoError ){ 
     2271            PA_DEBUG(("OpenStream ERROR13\n")); 
     2272            goto error; 
     2273        } 
     2274        callbackBufferProcessorInited = TRUE; 
     2275 
     2276        /* Initialize the blocking i/o buffer processor. */ 
     2277        result = PaUtil_InitializeBufferProcessor(&stream->blockingState->bufferProcessor, 
     2278                                                   inputChannelCount                     , 
     2279                                                   inputSampleFormat                     , /* User format. */ 
     2280                                                   inputSampleFormat & ~paNonInterleaved , /* Ring buffer. */ 
     2281                                                   outputChannelCount                    , 
     2282                                                   outputSampleFormat                    , /* User format. */ 
     2283                                                   outputSampleFormat & ~paNonInterleaved, /* Ring buffer. */ 
     2284                                                   sampleRate                            , 
     2285                                                   paClipOff | paDitherOff               , /* Don't use dither nor clipping. */ 
     2286                                                   framesPerBuffer                       , /* Frames per user buffer. */ 
     2287                                                   framesPerBuffer                       , /* Frames per ring buffer block. */ 
     2288                                                   paUtilBoundedHostBufferSize           , 
     2289                                                   NULL, NULL                            );/* No callback! */ 
     2290        if( result != paNoError ){ 
     2291            PA_DEBUG(("ERROR! Blocking i/o buffer processor initialization failed in OpenStream()\n")); 
     2292            goto error; 
     2293        } 
     2294        blockingBufferProcessorInited = TRUE; 
     2295 
     2296        /* If input is requested. */ 
     2297        if( inputChannelCount ) 
     2298        { 
     2299            /* Create the callback sync-event. */ 
     2300            stream->blockingState->readFramesReadyEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); 
     2301            if( stream->blockingState->readFramesReadyEvent == NULL ) 
     2302            { 
     2303                result = paUnanticipatedHostError; 
     2304                PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() ); 
     2305                PA_DEBUG(("ERROR! Blocking i/o \"read frames ready\" event creation failed in OpenStream()\n")); 
     2306                goto error; 
     2307            } 
     2308            blockingReadFramesReadyEventInitialized = 1; 
     2309 
     2310 
     2311            /* Create pointer buffer to access non-interleaved data in ReadStream() */ 
     2312            stream->blockingState->readStreamBuffer = (void**)PaUtil_AllocateMemory( sizeof(void*) * inputChannelCount ); 
     2313            if( !stream->blockingState->readStreamBuffer ) 
     2314            { 
     2315                result = paInsufficientMemory; 
     2316                PA_DEBUG(("ERROR! Blocking i/o read stream buffer allocation failed in OpenStream()\n")); 
     2317                goto error; 
     2318            } 
     2319 
     2320            /* The ring buffer should store as many data blocks as needed 
     2321               to achieve the requested latency. Whereas it must be large 
     2322               enough to store at least two complete data blocks. 
     2323 
     2324               1) Determine the amount of latency to be added to the 
     2325                  prefered ASIO latency. 
     2326               2) Make sure we have at lest one additional latency frame. 
     2327               3) Divide the number of frames by the desired block size to 
     2328                  get the number (rounded up to pure integer) of blocks to 
     2329                  be stored in the buffer. 
     2330               4) Add one additional block for block processing and convert 
     2331                  to samples frames. 
     2332               5) Get the next larger (or equal) power-of-two buffer size. 
     2333             */ 
     2334            lBlockingBufferSize = suggestedInputLatencyFrames - stream->inputLatency; 
     2335            lBlockingBufferSize = (lBlockingBufferSize > 0) ? lBlockingBufferSize : 1; 
     2336            lBlockingBufferSize = (lBlockingBufferSize + framesPerBuffer - 1) / framesPerBuffer; 
     2337            lBlockingBufferSize = (lBlockingBufferSize + 1) * framesPerBuffer; 
     2338 
     2339            /* Get the next larger or equal power-of-two buffersize. */ 
     2340            lBlockingBufferSizePow2 = 1; 
     2341            while( lBlockingBufferSize > (lBlockingBufferSizePow2<<=1) ); 
     2342            lBlockingBufferSize = lBlockingBufferSizePow2; 
     2343 
     2344            /* Compute total intput latency in seconds */ 
     2345            stream->streamRepresentation.streamInfo.inputLatency = 
     2346                (double)( PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor               ) 
     2347                        + PaUtil_GetBufferProcessorInputLatency(&stream->blockingState->bufferProcessor) 
     2348                        + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer 
     2349                        + stream->inputLatency ) 
     2350                / sampleRate; 
     2351 
     2352            /* The code below prints the ASIO latency which doesn't include 
     2353               the buffer processor latency nor the blocking i/o latency. It 
     2354               reports the added latency separately. 
     2355            */ 
     2356            PA_DEBUG(("PaAsio : ASIO InputLatency = %ld (%ld ms),\n         added buffProc:%ld (%ld ms),\n         added blocking:%ld (%ld ms)\n", 
     2357                stream->inputLatency, 
     2358                (long)( stream->inputLatency * (1000.0 / sampleRate) ), 
     2359                PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor), 
     2360                (long)( PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor) * (1000.0 / sampleRate) ), 
     2361                PaUtil_GetBufferProcessorInputLatency(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer, 
     2362                (long)( (PaUtil_GetBufferProcessorInputLatency(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer) * (1000.0 / sampleRate) ) 
     2363                )); 
     2364 
     2365            /* Determine the size of ring buffer in bytes. */ 
     2366            lBytesPerFrame = inputChannelCount * Pa_GetSampleSize(inputSampleFormat ); 
     2367 
     2368            /* Allocate the blocking i/o input ring buffer memory. */ 
     2369            stream->blockingState->readRingBufferData = (void*)PaUtil_AllocateMemory( lBlockingBufferSize * lBytesPerFrame ); 
     2370            if( !stream->blockingState->readRingBufferData ) 
     2371            { 
     2372                result = paInsufficientMemory; 
     2373                PA_DEBUG(("ERROR! Blocking i/o input ring buffer allocation failed in OpenStream()\n")); 
     2374                goto error; 
     2375            } 
     2376 
     2377            /* Initialize the input ring buffer struct. */ 
     2378            PaUtil_InitializeRingBuffer( &stream->blockingState->readRingBuffer    , 
     2379                                          lBytesPerFrame                           , 
     2380                                          lBlockingBufferSize                      , 
     2381                                          stream->blockingState->readRingBufferData ); 
     2382        } 
     2383 
     2384        /* If output is requested. */ 
     2385        if( outputChannelCount ) 
     2386        { 
     2387            stream->blockingState->writeBuffersReadyEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); 
     2388            if( stream->blockingState->writeBuffersReadyEvent == NULL ) 
     2389            { 
     2390                result = paUnanticipatedHostError; 
     2391                PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() ); 
     2392                PA_DEBUG(("ERROR! Blocking i/o \"write buffers ready\" event creation failed in OpenStream()\n")); 
     2393                goto error; 
     2394            } 
     2395            blockingWriteBuffersReadyEventInitialized = 1; 
     2396 
     2397            /* Create pointer buffer to access non-interleaved data in WriteStream() */ 
     2398            stream->blockingState->writeStreamBuffer = (const void**)PaUtil_AllocateMemory( sizeof(const void*) * outputChannelCount ); 
     2399            if( !stream->blockingState->writeStreamBuffer ) 
     2400            { 
     2401                result = paInsufficientMemory; 
     2402                PA_DEBUG(("ERROR! Blocking i/o write stream buffer allocation failed in OpenStream()\n")); 
     2403                goto error; 
     2404            } 
     2405 
     2406            /* The ring buffer should store as many data blocks as needed 
     2407               to achieve the requested latency. Whereas it must be large 
     2408               enough to store at least two complete data blocks. 
     2409 
     2410               1) Determine the amount of latency to be added to the 
     2411                  prefered ASIO latency. 
     2412               2) Make sure we have at lest one additional latency frame. 
     2413               3) Divide the number of frames by the desired block size to 
     2414                  get the number (rounded up to pure integer) of blocks to 
     2415                  be stored in the buffer. 
     2416               4) Add one additional block for block processing and convert 
     2417                  to samples frames. 
     2418               5) Get the next larger (or equal) power-of-two buffer size. 
     2419             */ 
     2420            lBlockingBufferSize = suggestedOutputLatencyFrames - stream->outputLatency; 
     2421            lBlockingBufferSize = (lBlockingBufferSize > 0) ? lBlockingBufferSize : 1; 
     2422            lBlockingBufferSize = (lBlockingBufferSize + framesPerBuffer - 1) / framesPerBuffer; 
     2423            lBlockingBufferSize = (lBlockingBufferSize + 1) * framesPerBuffer; 
     2424 
     2425            /* The buffer size (without the additional block) corresponds 
     2426               to the initial number of silent samples in the output ring 
     2427               buffer. */ 
     2428            stream->blockingState->writeRingBufferInitialFrames = lBlockingBufferSize - framesPerBuffer; 
     2429 
     2430            /* Get the next larger or equal power-of-two buffersize. */ 
     2431            lBlockingBufferSizePow2 = 1; 
     2432            while( lBlockingBufferSize > (lBlockingBufferSizePow2<<=1) ); 
     2433            lBlockingBufferSize = lBlockingBufferSizePow2; 
     2434 
     2435            /* Compute total output latency in seconds */ 
     2436            stream->streamRepresentation.streamInfo.outputLatency = 
     2437                (double)( PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor               ) 
     2438                        + PaUtil_GetBufferProcessorOutputLatency(&stream->blockingState->bufferProcessor) 
     2439                        + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer 
     2440                        + stream->outputLatency ) 
     2441                / sampleRate; 
     2442 
     2443            /* The code below prints the ASIO latency which doesn't include 
     2444               the buffer processor latency nor the blocking i/o latency. It 
     2445               reports the added latency separately. 
     2446            */ 
     2447            PA_DEBUG(("PaAsio : ASIO OutputLatency = %ld (%ld ms),\n         added buffProc:%ld (%ld ms),\n         added blocking:%ld (%ld ms)\n", 
     2448                stream->outputLatency, 
     2449                (long)( stream->inputLatency * (1000.0 / sampleRate) ), 
     2450                PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor), 
     2451                (long)( PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor) * (1000.0 / sampleRate) ), 
     2452                PaUtil_GetBufferProcessorOutputLatency(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer, 
     2453                (long)( (PaUtil_GetBufferProcessorOutputLatency(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer) * (1000.0 / sampleRate) ) 
     2454                )); 
     2455 
     2456            /* Determine the size of ring buffer in bytes. */ 
     2457            lBytesPerFrame = outputChannelCount * Pa_GetSampleSize(outputSampleFormat); 
     2458 
     2459            /* Allocate the blocking i/o output ring buffer memory. */ 
     2460            stream->blockingState->writeRingBufferData = (void*)PaUtil_AllocateMemory( lBlockingBufferSize * lBytesPerFrame ); 
     2461            if( !stream->blockingState->writeRingBufferData ) 
     2462            { 
     2463                result = paInsufficientMemory; 
     2464                PA_DEBUG(("ERROR! Blocking i/o output ring buffer allocation failed in OpenStream()\n")); 
     2465                goto error; 
     2466            } 
     2467 
     2468            /* Initialize the output ring buffer struct. */ 
     2469            PaUtil_InitializeRingBuffer( &stream->blockingState->writeRingBuffer    , 
     2470                                          lBytesPerFrame                            , 
     2471                                          lBlockingBufferSize                       , 
     2472                                          stream->blockingState->writeRingBufferData ); 
     2473        } 
     2474 
     2475        stream->streamRepresentation.streamInfo.sampleRate = sampleRate; 
     2476 
     2477 
     2478    } 
     2479    else /* Using callback interface... */ 
     2480    { 
     2481        result =  PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, 
     2482                        inputChannelCount, inputSampleFormat, hostInputSampleFormat, 
     2483                        outputChannelCount, outputSampleFormat, hostOutputSampleFormat, 
     2484                        sampleRate, streamFlags, framesPerBuffer, 
     2485                        framesPerHostBuffer, paUtilFixedHostBufferSize, 
     2486                        streamCallback, userData ); 
     2487        if( result != paNoError ){ 
     2488            PA_DEBUG(("OpenStream ERROR13\n")); 
     2489            goto error; 
     2490        } 
     2491        callbackBufferProcessorInited = TRUE; 
     2492 
     2493        stream->streamRepresentation.streamInfo.inputLatency = 
     2494                (double)( PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor) 
     2495                    + stream->inputLatency) / sampleRate;   // seconds 
     2496        stream->streamRepresentation.streamInfo.outputLatency = 
     2497                (double)( PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor) 
     2498                    + stream->outputLatency) / sampleRate; // seconds 
     2499        stream->streamRepresentation.streamInfo.sampleRate = sampleRate; 
     2500 
     2501        // the code below prints the ASIO latency which doesn't include the 
     2502        // buffer processor latency. it reports the added latency separately 
     2503        PA_DEBUG(("PaAsio : ASIO InputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n", 
     2504                stream->inputLatency, 
     2505                (long)((stream->inputLatency*1000)/ sampleRate),   
     2506                PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor), 
     2507                (long)((PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)*1000)/ sampleRate) 
     2508                )); 
     2509 
     2510        PA_DEBUG(("PaAsio : ASIO OuputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n", 
     2511                stream->outputLatency,