To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

The primary repository for this project is hosted at https://github.com/sonic-visualiser/sv-dependency-builds .
This repository is a read-only copy which is updated automatically every hour.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / src / portaudio_20161030_catalina_patch / src / hostapi / asio / pa_asio.cpp @ 164:9fa11135915a

History | View | Annotate | Download (159 KB)

1
/*
2
 * $Id$
3
 * Portable Audio I/O Library for ASIO Drivers
4
 *
5
 * Author: Stephane Letz
6
 * Based on the Open Source API proposed by Ross Bencina
7
 * 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)
10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining
12
 * a copy of this software and associated documentation files
13
 * (the "Software"), to deal in the Software without restriction,
14
 * including without limitation the rights to use, copy, modify, merge,
15
 * publish, distribute, sublicense, and/or sell copies of the Software,
16
 * and to permit persons to whom the Software is furnished to do so,
17
 * subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be
20
 * included in all copies or substantial portions of the Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
26
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
27
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
 */
30

    
31
/*
32
 * The text above constitutes the entire PortAudio license; however, 
33
 * the PortAudio community also makes the following non-binding requests:
34
 *
35
 * Any person wishing to distribute modifications to the Software is
36
 * requested to send the modifications to the original developer so that
37
 * they can be incorporated into the canonical version. It is also 
38
 * requested that these non-binding requests be included along with the 
39
 * license above.
40
 */
41

    
42
/* Modification History
43

44
        08-03-01 First version : Stephane Letz
45
        08-06-01 Tweaks for PC, use C++, buffer allocation, Float32 to Int32 conversion : Phil Burk
46
        08-20-01 More conversion, PA_StreamTime, Pa_GetHostError : Stephane Letz
47
        08-21-01 PaUInt8 bug correction, implementation of ASIOSTFloat32LSB and ASIOSTFloat32MSB native formats : Stephane Letz
48
        08-24-01 MAX_INT32_FP hack, another Uint8 fix : Stephane and Phil
49
        08-27-01 Implementation of hostBufferSize < userBufferSize case, better management of the ouput buffer when
50
                 the stream is stopped : Stephane Letz
51
        08-28-01 Check the stream pointer for null in bufferSwitchTimeInfo, correct bug in bufferSwitchTimeInfo when
52
                 the stream is stopped : Stephane Letz
53
        10-12-01 Correct the PaHost_CalcNumHostBuffers function: computes FramesPerHostBuffer to be the lowest that
54
                 respect requested FramesPerUserBuffer and userBuffersPerHostBuffer : Stephane Letz
55
        10-26-01 Management of hostBufferSize and userBufferSize of any size : Stephane Letz
56
        10-27-01 Improve calculus of hostBufferSize to be multiple or divisor of userBufferSize if possible : Stephane and Phil
57
        10-29-01 Change MAX_INT32_FP to (2147483520.0f) to prevent roundup to 0x80000000 : Phil Burk
58
        10-31-01 Clear the ouput buffer and user buffers in PaHost_StartOutput, correct bug in GetFirstMultiple : Stephane Letz
59
        11-06-01 Rename functions : Stephane Letz
60
        11-08-01 New Pa_ASIO_Adaptor_Init function to init Callback adpatation variables, cleanup of Pa_ASIO_Callback_Input: Stephane Letz
61
        11-29-01 Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo ; Phil Burk
62
        01-03-02 Desallocate all resources in PaHost_Term for cases where Pa_CloseStream is not called properly :  Stephane Letz
63
        02-01-02 Cleanup, test of multiple-stream opening : Stephane Letz
64
        19-02-02 New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows : Stephane Letz
65
        09-04-02 Correct error code management in PaHost_Term, removes various compiler warning : Stephane Letz
66
        12-04-02 Add Mac includes for <Devices.h> and <Timer.h> : Phil Burk
67
        13-04-02 Removes another compiler warning : Stephane Letz
68
        30-04-02 Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better error handling : D Viens, P Burk, S Letz
69
        12-06-02 Rehashed into new multi-api infrastructure, added support for all ASIO sample formats : Ross Bencina
70
        18-06-02 Added pa_asio.h, PaAsio_GetAvailableLatencyValues() : Ross B.
71
        21-06-02 Added SelectHostBufferSize() which selects host buffer size based on user latency parameters : Ross Bencina
72
        ** NOTE  maintanance history is now stored in CVS **
73
*/
74

    
75
/** @file
76
    @ingroup hostapi_src
77

78
    Note that specific support for paInputUnderflow, paOutputOverflow and
79
    paNeverDropInput is not necessary or possible with this driver due to the
80
    synchronous full duplex double-buffered architecture of ASIO.
81
*/
82

    
83

    
84
#include <stdio.h>
85
#include <assert.h>
86
#include <string.h>
87
//#include <values.h>
88
#include <new>
89

    
90
#include <windows.h>
91
#include <mmsystem.h>
92

    
93
#include "portaudio.h"
94
#include "pa_asio.h"
95
#include "pa_util.h"
96
#include "pa_allocation.h"
97
#include "pa_hostapi.h"
98
#include "pa_stream.h"
99
#include "pa_cpuload.h"
100
#include "pa_process.h"
101
#include "pa_debugprint.h"
102
#include "pa_ringbuffer.h"
103

    
104
#include "pa_win_coinitialize.h"
105

    
106
/* This version of pa_asio.cpp is currently only targetted at Win32,
107
   It would require a few tweaks to work with pre-OS X Macintosh.
108
   To make configuration easier, we define WIN32 here to make sure
109
   that the ASIO SDK knows this is Win32.
110
*/
111
#ifndef WIN32
112
#define WIN32
113
#endif
114

    
115
#include "asiosys.h"
116
#include "asio.h"
117
#include "asiodrivers.h"
118
#include "iasiothiscallresolver.h"
119

    
120
/*
121
#if MAC
122
#include <Devices.h>
123
#include <Timer.h>
124
#include <Math64.h>
125
#else
126
*/
127
/*
128
#include <math.h>
129
#include <windows.h>
130
#include <mmsystem.h>
131
*/
132
/*
133
#endif
134
*/
135

    
136

    
137
/* winmm.lib is needed for timeGetTime() (this is in winmm.a if you're using gcc) */
138
#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */
139
#pragma comment(lib, "winmm.lib")
140
#endif
141

    
142

    
143
/* external reference to ASIO SDK's asioDrivers.
144

145
 This is a bit messy because we want to explicitly manage 
146
 allocation/deallocation of this structure, but some layers of the SDK 
147
 which we currently use (eg the implementation in asio.cpp) still
148
 use this global version.
149

150
 For now we keep it in sync with our local instance in the host
151
 API representation structure, but later we should be able to remove
152
 all dependence on it.
153
*/
154
extern AsioDrivers* asioDrivers;
155

    
156

    
157
/* We are trying to be compatible with CARBON but this has not been thoroughly tested. */
158
/* not tested at all since new V19 code was introduced. */
159
#define CARBON_COMPATIBLE  (0)
160

    
161

    
162
/* prototypes for functions declared in this file */
163

    
164
extern "C" PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );
165
static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
166
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
167
                           PaStream** s,
168
                           const PaStreamParameters *inputParameters,
169
                           const PaStreamParameters *outputParameters,
170
                           double sampleRate,
171
                           unsigned long framesPerBuffer,
172
                           PaStreamFlags streamFlags,
173
                           PaStreamCallback *streamCallback,
174
                           void *userData );
175
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
176
                                  const PaStreamParameters *inputParameters,
177
                                  const PaStreamParameters *outputParameters,
178
                                  double sampleRate );
179
static PaError CloseStream( PaStream* stream );
180
static PaError StartStream( PaStream *stream );
181
static PaError StopStream( PaStream *stream );
182
static PaError AbortStream( PaStream *stream );
183
static PaError IsStreamStopped( PaStream *s );
184
static PaError IsStreamActive( PaStream *stream );
185
static PaTime GetStreamTime( PaStream *stream );
186
static double GetStreamCpuLoad( PaStream* stream );
187
static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
188
static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
189
static signed long GetStreamReadAvailable( PaStream* stream );
190
static signed long GetStreamWriteAvailable( PaStream* stream );
191

    
192
/* Blocking i/o callback function. */
193
static int BlockingIoPaCallback(const void                     *inputBuffer    ,
194
                                      void                     *outputBuffer   ,
195
                                      unsigned long             framesPerBuffer,
196
                                const PaStreamCallbackTimeInfo *timeInfo       ,
197
                                      PaStreamCallbackFlags     statusFlags    ,
198
                                      void                     *userData       );
199

    
200
/* our ASIO callback functions */
201

    
202
static void bufferSwitch(long index, ASIOBool processNow);
203
static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow);
204
static void sampleRateChanged(ASIOSampleRate sRate);
205
static long asioMessages(long selector, long value, void* message, double* opt);
206

    
207
static ASIOCallbacks asioCallbacks_ =
208
    { bufferSwitch, sampleRateChanged, asioMessages, bufferSwitchTimeInfo };
209

    
210

    
211
#define PA_ASIO_SET_LAST_HOST_ERROR( errorCode, errorText ) \
212
    PaUtil_SetLastHostErrorInfo( paASIO, errorCode, errorText )
213

    
214

    
215
static void PaAsio_SetLastSystemError( DWORD errorCode )
216
{
217
    LPVOID lpMsgBuf;
218
    FormatMessage(
219
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
220
        NULL,
221
        errorCode,
222
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
223
        (LPTSTR) &lpMsgBuf,
224
        0,
225
        NULL
226
    );
227
    PaUtil_SetLastHostErrorInfo( paASIO, errorCode, (const char*)lpMsgBuf );
228
    LocalFree( lpMsgBuf );
229
}
230

    
231
#define PA_ASIO_SET_LAST_SYSTEM_ERROR( errorCode ) \
232
    PaAsio_SetLastSystemError( errorCode )
233

    
234

    
235
static const char* PaAsio_GetAsioErrorText( ASIOError asioError )
236
{
237
    const char *result;
238

    
239
    switch( asioError ){
240
        case ASE_OK:
241
        case ASE_SUCCESS:           result = "Success"; break;
242
        case ASE_NotPresent:        result = "Hardware input or output is not present or available"; break;
243
        case ASE_HWMalfunction:     result = "Hardware is malfunctioning"; break;
244
        case ASE_InvalidParameter:  result = "Input parameter invalid"; break;
245
        case ASE_InvalidMode:       result = "Hardware is in a bad mode or used in a bad mode"; break;
246
        case ASE_SPNotAdvancing:    result = "Hardware is not running when sample position is inquired"; break;
247
        case ASE_NoClock:           result = "Sample clock or rate cannot be determined or is not present"; break;
248
        case ASE_NoMemory:          result = "Not enough memory for completing the request"; break;
249
        default:                    result = "Unknown ASIO error"; break;
250
    }
251

    
252
    return result;
253
}
254

    
255

    
256
#define PA_ASIO_SET_LAST_ASIO_ERROR( asioError ) \
257
    PaUtil_SetLastHostErrorInfo( paASIO, asioError, PaAsio_GetAsioErrorText( asioError ) )
258

    
259

    
260

    
261

    
262
// Atomic increment and decrement operations
263
#if MAC
264
    /* need to be implemented on Mac */
265
    inline long PaAsio_AtomicIncrement(volatile long* v) {return ++(*const_cast<long*>(v));}
266
    inline long PaAsio_AtomicDecrement(volatile long* v) {return --(*const_cast<long*>(v));}
267
#elif WINDOWS
268
    inline long PaAsio_AtomicIncrement(volatile long* v) {return InterlockedIncrement(const_cast<long*>(v));}
269
    inline long PaAsio_AtomicDecrement(volatile long* v) {return InterlockedDecrement(const_cast<long*>(v));}
270
#endif
271

    
272

    
273

    
274
typedef struct PaAsioDriverInfo
275
{
276
    ASIODriverInfo asioDriverInfo;
277
    long inputChannelCount, outputChannelCount;
278
    long bufferMinSize, bufferMaxSize, bufferPreferredSize, bufferGranularity;
279
    bool postOutput;
280
}
281
PaAsioDriverInfo;
282

    
283

    
284
/* PaAsioHostApiRepresentation - host api datastructure specific to this implementation */
285

    
286
typedef struct
287
{
288
    PaUtilHostApiRepresentation inheritedHostApiRep;
289
    PaUtilStreamInterface callbackStreamInterface;
290
    PaUtilStreamInterface blockingStreamInterface;
291

    
292
    PaUtilAllocationGroup *allocations;
293

    
294
    PaWinUtilComInitializationResult comInitializationResult;
295

    
296
    AsioDrivers *asioDrivers;
297
    void *systemSpecific;
298
    
299
    /* the ASIO C API only allows one ASIO driver to be open at a time,
300
        so we keep track of whether we have the driver open here, and
301
        use this information to return errors from OpenStream if the
302
        driver is already open.
303

304
        openAsioDeviceIndex will be PaNoDevice if there is no device open
305
        and a valid pa_asio (not global) device index otherwise.
306

307
        openAsioDriverInfo is populated with the driver info for the
308
        currently open device (if any)
309
    */
310
    PaDeviceIndex openAsioDeviceIndex;
311
    PaAsioDriverInfo openAsioDriverInfo;
312
}
313
PaAsioHostApiRepresentation;
314

    
315

    
316
/*
317
    Retrieve <driverCount> driver names from ASIO, returned in a char**
318
    allocated in <group>.
319
*/
320
static char **GetAsioDriverNames( PaAsioHostApiRepresentation *asioHostApi, PaUtilAllocationGroup *group, long driverCount )
321
{
322
    char **result = 0;
323
    int i;
324

    
325
    result =(char**)PaUtil_GroupAllocateMemory(
326
            group, sizeof(char*) * driverCount );
327
    if( !result )
328
        goto error;
329

    
330
    result[0] = (char*)PaUtil_GroupAllocateMemory(
331
            group, 32 * driverCount );
332
    if( !result[0] )
333
        goto error;
334

    
335
    for( i=0; i<driverCount; ++i )
336
        result[i] = result[0] + (32 * i);
337

    
338
    asioHostApi->asioDrivers->getDriverNames( result, driverCount );
339

    
340
error:
341
    return result;
342
}
343

    
344

    
345
static PaSampleFormat AsioSampleTypeToPaNativeSampleFormat(ASIOSampleType type)
346
{
347
    switch (type) {
348
        case ASIOSTInt16MSB:
349
        case ASIOSTInt16LSB:
350
                return paInt16;
351

    
352
        case ASIOSTFloat32MSB:
353
        case ASIOSTFloat32LSB:
354
        case ASIOSTFloat64MSB:
355
        case ASIOSTFloat64LSB:
356
                return paFloat32;
357

    
358
        case ASIOSTInt32MSB:
359
        case ASIOSTInt32LSB:
360
        case ASIOSTInt32MSB16:
361
        case ASIOSTInt32LSB16:
362
        case ASIOSTInt32MSB18:
363
        case ASIOSTInt32MSB20:
364
        case ASIOSTInt32MSB24:
365
        case ASIOSTInt32LSB18:
366
        case ASIOSTInt32LSB20:
367
        case ASIOSTInt32LSB24:
368
                return paInt32;
369

    
370
        case ASIOSTInt24MSB:
371
        case ASIOSTInt24LSB:
372
                return paInt24;
373

    
374
        default:
375
                return paCustomFormat;
376
    }
377
}
378

    
379
void AsioSampleTypeLOG(ASIOSampleType type)
380
{
381
    switch (type) {
382
        case ASIOSTInt16MSB:  PA_DEBUG(("ASIOSTInt16MSB\n"));  break;
383
        case ASIOSTInt16LSB:  PA_DEBUG(("ASIOSTInt16LSB\n"));  break;
384
        case ASIOSTFloat32MSB:PA_DEBUG(("ASIOSTFloat32MSB\n"));break;
385
        case ASIOSTFloat32LSB:PA_DEBUG(("ASIOSTFloat32LSB\n"));break;
386
        case ASIOSTFloat64MSB:PA_DEBUG(("ASIOSTFloat64MSB\n"));break;
387
        case ASIOSTFloat64LSB:PA_DEBUG(("ASIOSTFloat64LSB\n"));break;
388
        case ASIOSTInt32MSB:  PA_DEBUG(("ASIOSTInt32MSB\n"));  break;
389
        case ASIOSTInt32LSB:  PA_DEBUG(("ASIOSTInt32LSB\n"));  break;
390
        case ASIOSTInt32MSB16:PA_DEBUG(("ASIOSTInt32MSB16\n"));break;
391
        case ASIOSTInt32LSB16:PA_DEBUG(("ASIOSTInt32LSB16\n"));break;
392
        case ASIOSTInt32MSB18:PA_DEBUG(("ASIOSTInt32MSB18\n"));break;
393
        case ASIOSTInt32MSB20:PA_DEBUG(("ASIOSTInt32MSB20\n"));break;
394
        case ASIOSTInt32MSB24:PA_DEBUG(("ASIOSTInt32MSB24\n"));break;
395
        case ASIOSTInt32LSB18:PA_DEBUG(("ASIOSTInt32LSB18\n"));break;
396
        case ASIOSTInt32LSB20:PA_DEBUG(("ASIOSTInt32LSB20\n"));break;
397
        case ASIOSTInt32LSB24:PA_DEBUG(("ASIOSTInt32LSB24\n"));break;
398
        case ASIOSTInt24MSB:  PA_DEBUG(("ASIOSTInt24MSB\n"));  break;
399
        case ASIOSTInt24LSB:  PA_DEBUG(("ASIOSTInt24LSB\n"));  break;
400
        default:              PA_DEBUG(("Custom Format%d\n",type));break;
401

    
402
    }
403
}
404

    
405
static int BytesPerAsioSample( ASIOSampleType sampleType )
406
{
407
    switch (sampleType) {
408
        case ASIOSTInt16MSB:
409
        case ASIOSTInt16LSB:
410
            return 2;
411

    
412
        case ASIOSTFloat64MSB:
413
        case ASIOSTFloat64LSB:
414
            return 8;
415

    
416
        case ASIOSTFloat32MSB:
417
        case ASIOSTFloat32LSB:
418
        case ASIOSTInt32MSB:
419
        case ASIOSTInt32LSB:
420
        case ASIOSTInt32MSB16:
421
        case ASIOSTInt32LSB16:
422
        case ASIOSTInt32MSB18:
423
        case ASIOSTInt32MSB20:
424
        case ASIOSTInt32MSB24:
425
        case ASIOSTInt32LSB18:
426
        case ASIOSTInt32LSB20:
427
        case ASIOSTInt32LSB24:
428
            return 4;
429

    
430
        case ASIOSTInt24MSB:
431
        case ASIOSTInt24LSB:
432
            return 3;
433

    
434
        default:
435
            return 0;
436
    }
437
}
438

    
439

    
440
static void Swap16( void *buffer, long shift, long count )
441
{
442
    unsigned short *p = (unsigned short*)buffer;
443
    unsigned short temp;
444
    (void) shift; /* unused parameter */
445

    
446
    while( count-- )
447
    {
448
        temp = *p;
449
        *p++ = (unsigned short)((temp<<8) | (temp>>8));
450
    }
451
}
452

    
453
static void Swap24( void *buffer, long shift, long count )
454
{
455
    unsigned char *p = (unsigned char*)buffer;
456
    unsigned char temp;
457
    (void) shift; /* unused parameter */
458

    
459
    while( count-- )
460
    {
461
        temp = *p;
462
        *p = *(p+2);
463
        *(p+2) = temp;
464
        p += 3;
465
    }
466
}
467

    
468
#define PA_SWAP32_( x ) ((x>>24) | ((x>>8)&0xFF00) | ((x<<8)&0xFF0000) | (x<<24));
469

    
470
static void Swap32( void *buffer, long shift, long count )
471
{
472
    unsigned long *p = (unsigned long*)buffer;
473
    unsigned long temp;
474
    (void) shift; /* unused parameter */
475

    
476
    while( count-- )
477
    {
478
        temp = *p;
479
        *p++ = PA_SWAP32_( temp);
480
    }
481
}
482

    
483
static void SwapShiftLeft32( void *buffer, long shift, long count )
484
{
485
    unsigned long *p = (unsigned long*)buffer;
486
    unsigned long temp;
487

    
488
    while( count-- )
489
    {
490
        temp = *p;
491
        temp = PA_SWAP32_( temp);
492
        *p++ = temp << shift;
493
    }
494
}
495

    
496
static void ShiftRightSwap32( void *buffer, long shift, long count )
497
{
498
    unsigned long *p = (unsigned long*)buffer;
499
    unsigned long temp;
500

    
501
    while( count-- )
502
    {
503
        temp = *p >> shift;
504
        *p++ = PA_SWAP32_( temp);
505
    }
506
}
507

    
508
static void ShiftLeft32( void *buffer, long shift, long count )
509
{
510
    unsigned long *p = (unsigned long*)buffer;
511
    unsigned long temp;
512

    
513
    while( count-- )
514
    {
515
        temp = *p;
516
        *p++ = temp << shift;
517
    }
518
}
519

    
520
static void ShiftRight32( void *buffer, long shift, long count )
521
{
522
    unsigned long *p = (unsigned long*)buffer;
523
    unsigned long temp;
524

    
525
    while( count-- )
526
    {
527
        temp = *p;
528
        *p++ = temp >> shift;
529
    }
530
}
531

    
532
#define PA_SWAP_( x, y ) temp=x; x = y; y = temp;
533

    
534
static void Swap64ConvertFloat64ToFloat32( void *buffer, long shift, long count )
535
{
536
    double *in = (double*)buffer;
537
    float *out = (float*)buffer;
538
    unsigned char *p;
539
    unsigned char temp;
540
    (void) shift; /* unused parameter */
541

    
542
    while( count-- )
543
    {
544
        p = (unsigned char*)in;
545
        PA_SWAP_( p[0], p[7] );
546
        PA_SWAP_( p[1], p[6] );
547
        PA_SWAP_( p[2], p[5] );
548
        PA_SWAP_( p[3], p[4] );
549

    
550
        *out++ = (float) (*in++);
551
    }
552
}
553

    
554
static void ConvertFloat64ToFloat32( void *buffer, long shift, long count )
555
{
556
    double *in = (double*)buffer;
557
    float *out = (float*)buffer;
558
    (void) shift; /* unused parameter */
559

    
560
    while( count-- )
561
        *out++ = (float) (*in++);
562
}
563

    
564
static void ConvertFloat32ToFloat64Swap64( void *buffer, long shift, long count )
565
{
566
    float *in = ((float*)buffer) + (count-1);
567
    double *out = ((double*)buffer) + (count-1);
568
    unsigned char *p;
569
    unsigned char temp;
570
    (void) shift; /* unused parameter */
571

    
572
    while( count-- )
573
    {
574
        *out = *in--;
575

    
576
        p = (unsigned char*)out;
577
        PA_SWAP_( p[0], p[7] );
578
        PA_SWAP_( p[1], p[6] );
579
        PA_SWAP_( p[2], p[5] );
580
        PA_SWAP_( p[3], p[4] );
581

    
582
        out--;
583
    }
584
}
585

    
586
static void ConvertFloat32ToFloat64( void *buffer, long shift, long count )
587
{
588
    float *in = ((float*)buffer) + (count-1);
589
    double *out = ((double*)buffer) + (count-1);
590
    (void) shift; /* unused parameter */
591

    
592
    while( count-- )
593
        *out-- = *in--;
594
}
595

    
596
#ifdef MAC
597
#define PA_MSB_IS_NATIVE_
598
#undef PA_LSB_IS_NATIVE_
599
#endif
600

    
601
#ifdef WINDOWS
602
#undef PA_MSB_IS_NATIVE_
603
#define PA_LSB_IS_NATIVE_
604
#endif
605

    
606
typedef void PaAsioBufferConverter( void *, long, long );
607

    
608
static void SelectAsioToPaConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift )
609
{
610
    *shift = 0;
611
    *converter = 0;
612

    
613
    switch (type) {
614
        case ASIOSTInt16MSB:
615
            /* dest: paInt16, no conversion necessary, possible byte swap*/
616
            #ifdef PA_LSB_IS_NATIVE_
617
                *converter = Swap16;
618
            #endif
619
            break;
620
        case ASIOSTInt16LSB:
621
            /* dest: paInt16, no conversion necessary, possible byte swap*/
622
            #ifdef PA_MSB_IS_NATIVE_
623
                *converter = Swap16;
624
            #endif
625
            break;
626
        case ASIOSTFloat32MSB:
627
            /* dest: paFloat32, no conversion necessary, possible byte swap*/
628
            #ifdef PA_LSB_IS_NATIVE_
629
                *converter = Swap32;
630
            #endif
631
            break;
632
        case ASIOSTFloat32LSB:
633
            /* dest: paFloat32, no conversion necessary, possible byte swap*/
634
            #ifdef PA_MSB_IS_NATIVE_
635
                *converter = Swap32;
636
            #endif
637
            break;
638
        case ASIOSTFloat64MSB:
639
            /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
640
            #ifdef PA_LSB_IS_NATIVE_
641
                *converter = Swap64ConvertFloat64ToFloat32;
642
            #else
643
                *converter = ConvertFloat64ToFloat32;
644
            #endif
645
            break;
646
        case ASIOSTFloat64LSB:
647
            /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
648
            #ifdef PA_MSB_IS_NATIVE_
649
                *converter = Swap64ConvertFloat64ToFloat32;
650
            #else
651
                *converter = ConvertFloat64ToFloat32;
652
            #endif
653
            break;
654
        case ASIOSTInt32MSB:
655
            /* dest: paInt32, no conversion necessary, possible byte swap */
656
            #ifdef PA_LSB_IS_NATIVE_
657
                *converter = Swap32;
658
            #endif
659
            break;
660
        case ASIOSTInt32LSB:
661
            /* dest: paInt32, no conversion necessary, possible byte swap */
662
            #ifdef PA_MSB_IS_NATIVE_
663
                *converter = Swap32;
664
            #endif
665
            break;
666
        case ASIOSTInt32MSB16:
667
            /* dest: paInt32, 16 bit shift, possible byte swap */
668
            #ifdef PA_LSB_IS_NATIVE_
669
                *converter = SwapShiftLeft32;
670
            #else
671
                *converter = ShiftLeft32;
672
            #endif
673
            *shift = 16;
674
            break;
675
        case ASIOSTInt32MSB18:
676
            /* dest: paInt32, 14 bit shift, possible byte swap */
677
            #ifdef PA_LSB_IS_NATIVE_
678
                *converter = SwapShiftLeft32;
679
            #else
680
                *converter = ShiftLeft32;
681
            #endif
682
            *shift = 14;
683
            break;
684
        case ASIOSTInt32MSB20:
685
            /* dest: paInt32, 12 bit shift, possible byte swap */
686
            #ifdef PA_LSB_IS_NATIVE_
687
                *converter = SwapShiftLeft32;
688
            #else
689
                *converter = ShiftLeft32;
690
            #endif
691
            *shift = 12;
692
            break;
693
        case ASIOSTInt32MSB24:
694
            /* dest: paInt32, 8 bit shift, possible byte swap */
695
            #ifdef PA_LSB_IS_NATIVE_
696
                *converter = SwapShiftLeft32;
697
            #else
698
                *converter = ShiftLeft32;
699
            #endif
700
            *shift = 8;
701
            break;
702
        case ASIOSTInt32LSB16:
703
            /* dest: paInt32, 16 bit shift, possible byte swap */
704
            #ifdef PA_MSB_IS_NATIVE_
705
                *converter = SwapShiftLeft32;
706
            #else
707
                *converter = ShiftLeft32;
708
            #endif
709
            *shift = 16;
710
            break;
711
        case ASIOSTInt32LSB18:
712
            /* dest: paInt32, 14 bit shift, possible byte swap */
713
            #ifdef PA_MSB_IS_NATIVE_
714
                *converter = SwapShiftLeft32;
715
            #else
716
                *converter = ShiftLeft32;
717
            #endif
718
            *shift = 14;
719
            break;
720
        case ASIOSTInt32LSB20:
721
            /* dest: paInt32, 12 bit shift, possible byte swap */
722
            #ifdef PA_MSB_IS_NATIVE_
723
                *converter = SwapShiftLeft32;
724
            #else
725
                *converter = ShiftLeft32;
726
            #endif
727
            *shift = 12;
728
            break;
729
        case ASIOSTInt32LSB24:
730
            /* dest: paInt32, 8 bit shift, possible byte swap */
731
            #ifdef PA_MSB_IS_NATIVE_
732
                *converter = SwapShiftLeft32;
733
            #else
734
                *converter = ShiftLeft32;
735
            #endif
736
            *shift = 8;
737
            break;
738
        case ASIOSTInt24MSB:
739
            /* dest: paInt24, no conversion necessary, possible byte swap */
740
            #ifdef PA_LSB_IS_NATIVE_
741
                *converter = Swap24;
742
            #endif
743
            break;
744
        case ASIOSTInt24LSB:
745
            /* dest: paInt24, no conversion necessary, possible byte swap */
746
            #ifdef PA_MSB_IS_NATIVE_
747
                *converter = Swap24;
748
            #endif
749
            break;
750
    }
751
}
752

    
753

    
754
static void SelectPaToAsioConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift )
755
{
756
    *shift = 0;
757
    *converter = 0;
758

    
759
    switch (type) {
760
        case ASIOSTInt16MSB:
761
            /* src: paInt16, no conversion necessary, possible byte swap*/
762
            #ifdef PA_LSB_IS_NATIVE_
763
                *converter = Swap16;
764
            #endif
765
            break;
766
        case ASIOSTInt16LSB:
767
            /* src: paInt16, no conversion necessary, possible byte swap*/
768
            #ifdef PA_MSB_IS_NATIVE_
769
                *converter = Swap16;
770
            #endif
771
            break;
772
        case ASIOSTFloat32MSB:
773
            /* src: paFloat32, no conversion necessary, possible byte swap*/
774
            #ifdef PA_LSB_IS_NATIVE_
775
                *converter = Swap32;
776
            #endif
777
            break;
778
        case ASIOSTFloat32LSB:
779
            /* src: paFloat32, no conversion necessary, possible byte swap*/
780
            #ifdef PA_MSB_IS_NATIVE_
781
                *converter = Swap32;
782
            #endif
783
            break;
784
        case ASIOSTFloat64MSB:
785
            /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
786
            #ifdef PA_LSB_IS_NATIVE_
787
                *converter = ConvertFloat32ToFloat64Swap64;
788
            #else
789
                *converter = ConvertFloat32ToFloat64;
790
            #endif
791
            break;
792
        case ASIOSTFloat64LSB:
793
            /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
794
            #ifdef PA_MSB_IS_NATIVE_
795
                *converter = ConvertFloat32ToFloat64Swap64;
796
            #else
797
                *converter = ConvertFloat32ToFloat64;
798
            #endif
799
            break;
800
        case ASIOSTInt32MSB:
801
            /* src: paInt32, no conversion necessary, possible byte swap */
802
            #ifdef PA_LSB_IS_NATIVE_
803
                *converter = Swap32;
804
            #endif
805
            break;
806
        case ASIOSTInt32LSB:
807
            /* src: paInt32, no conversion necessary, possible byte swap */
808
            #ifdef PA_MSB_IS_NATIVE_
809
                *converter = Swap32;
810
            #endif
811
            break;
812
        case ASIOSTInt32MSB16:
813
            /* src: paInt32, 16 bit shift, possible byte swap */
814
            #ifdef PA_LSB_IS_NATIVE_
815
                *converter = ShiftRightSwap32;
816
            #else
817
                *converter = ShiftRight32;
818
            #endif
819
            *shift = 16;
820
            break;
821
        case ASIOSTInt32MSB18:
822
            /* src: paInt32, 14 bit shift, possible byte swap */
823
            #ifdef PA_LSB_IS_NATIVE_
824
                *converter = ShiftRightSwap32;
825
            #else
826
                *converter = ShiftRight32;
827
            #endif
828
            *shift = 14;
829
            break;
830
        case ASIOSTInt32MSB20:
831
            /* src: paInt32, 12 bit shift, possible byte swap */
832
            #ifdef PA_LSB_IS_NATIVE_
833
                *converter = ShiftRightSwap32;
834
            #else
835
                *converter = ShiftRight32;
836
            #endif
837
            *shift = 12;
838
            break;
839
        case ASIOSTInt32MSB24:
840
            /* src: paInt32, 8 bit shift, possible byte swap */
841
            #ifdef PA_LSB_IS_NATIVE_
842
                *converter = ShiftRightSwap32;
843
            #else
844
                *converter = ShiftRight32;
845
            #endif
846
            *shift = 8;
847
            break;
848
        case ASIOSTInt32LSB16:
849
            /* src: paInt32, 16 bit shift, possible byte swap */
850
            #ifdef PA_MSB_IS_NATIVE_
851
                *converter = ShiftRightSwap32;
852
            #else
853
                *converter = ShiftRight32;
854
            #endif
855
            *shift = 16;
856
            break;
857
        case ASIOSTInt32LSB18:
858
            /* src: paInt32, 14 bit shift, possible byte swap */
859
            #ifdef PA_MSB_IS_NATIVE_
860
                *converter = ShiftRightSwap32;
861
            #else
862
                *converter = ShiftRight32;
863
            #endif
864
            *shift = 14;
865
            break;
866
        case ASIOSTInt32LSB20:
867
            /* src: paInt32, 12 bit shift, possible byte swap */
868
            #ifdef PA_MSB_IS_NATIVE_
869
                *converter = ShiftRightSwap32;
870
            #else
871
                *converter = ShiftRight32;
872
            #endif
873
            *shift = 12;
874
            break;
875
        case ASIOSTInt32LSB24:
876
            /* src: paInt32, 8 bit shift, possible byte swap */
877
            #ifdef PA_MSB_IS_NATIVE_
878
                *converter = ShiftRightSwap32;
879
            #else
880
                *converter = ShiftRight32;
881
            #endif
882
            *shift = 8;
883
            break;
884
        case ASIOSTInt24MSB:
885
            /* src: paInt24, no conversion necessary, possible byte swap */
886
            #ifdef PA_LSB_IS_NATIVE_
887
                *converter = Swap24;
888
            #endif
889
            break;
890
        case ASIOSTInt24LSB:
891
            /* src: paInt24, no conversion necessary, possible byte swap */
892
            #ifdef PA_MSB_IS_NATIVE_
893
                *converter = Swap24;
894
            #endif
895
            break;
896
    }
897
}
898

    
899

    
900
typedef struct PaAsioDeviceInfo
901
{
902
    PaDeviceInfo commonDeviceInfo;
903
    long minBufferSize;
904
    long maxBufferSize;
905
    long preferredBufferSize;
906
    long bufferGranularity;
907

    
908
    ASIOChannelInfo *asioChannelInfos;
909
}
910
PaAsioDeviceInfo;
911

    
912

    
913
PaError PaAsio_GetAvailableBufferSizes( PaDeviceIndex device,
914
        long *minBufferSizeFrames, long *maxBufferSizeFrames, long *preferredBufferSizeFrames, long *granularity )
915
{
916
    PaError result;
917
    PaUtilHostApiRepresentation *hostApi;
918
    PaDeviceIndex hostApiDevice;
919

    
920
    result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
921

    
922
    if( result == paNoError )
923
    {
924
        result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
925

    
926
        if( result == paNoError )
927
        {
928
            PaAsioDeviceInfo *asioDeviceInfo =
929
                    (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
930

    
931
            *minBufferSizeFrames = asioDeviceInfo->minBufferSize;
932
            *maxBufferSizeFrames = asioDeviceInfo->maxBufferSize;
933
            *preferredBufferSizeFrames = asioDeviceInfo->preferredBufferSize;
934
            *granularity = asioDeviceInfo->bufferGranularity;
935
        }
936
    }
937

    
938
    return result;
939
}
940

    
941
/* Unload whatever we loaded in LoadAsioDriver().
942
*/
943
static void UnloadAsioDriver( void )
944
{
945
        ASIOExit();
946
}
947

    
948
/*
949
    load the asio driver named by <driverName> and return statistics about
950
    the driver in info. If no error occurred, the driver will remain open
951
    and must be closed by the called by calling UnloadAsioDriver() - if an error
952
    is returned the driver will already be unloaded.
953
*/
954
static PaError LoadAsioDriver( PaAsioHostApiRepresentation *asioHostApi, const char *driverName,
955
        PaAsioDriverInfo *driverInfo, void *systemSpecific )
956
{
957
    PaError result = paNoError;
958
    ASIOError asioError;
959
    int asioIsInitialized = 0;
960

    
961
    if( !asioHostApi->asioDrivers->loadDriver( const_cast<char*>(driverName) ) )
962
    {
963
        result = paUnanticipatedHostError;
964
        PA_ASIO_SET_LAST_HOST_ERROR( 0, "Failed to load ASIO driver" );
965
        goto error;
966
    }
967

    
968
    memset( &driverInfo->asioDriverInfo, 0, sizeof(ASIODriverInfo) );
969
    driverInfo->asioDriverInfo.asioVersion = 2;
970
    driverInfo->asioDriverInfo.sysRef = systemSpecific;
971
    if( (asioError = ASIOInit( &driverInfo->asioDriverInfo )) != ASE_OK )
972
    {
973
        result = paUnanticipatedHostError;
974
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
975
        goto error;
976
    }
977
    else
978
    {
979
        asioIsInitialized = 1;
980
    }
981

    
982
    if( (asioError = ASIOGetChannels(&driverInfo->inputChannelCount,
983
            &driverInfo->outputChannelCount)) != ASE_OK )
984
    {
985
        result = paUnanticipatedHostError;
986
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
987
        goto error;
988
    }
989

    
990
    if( (asioError = ASIOGetBufferSize(&driverInfo->bufferMinSize,
991
            &driverInfo->bufferMaxSize, &driverInfo->bufferPreferredSize,
992
            &driverInfo->bufferGranularity)) != ASE_OK )
993
    {
994
        result = paUnanticipatedHostError;
995
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
996
        goto error;
997
    }
998

    
999
    if( ASIOOutputReady() == ASE_OK )
1000
        driverInfo->postOutput = true;
1001
    else
1002
        driverInfo->postOutput = false;
1003

    
1004
    return result;
1005

    
1006
error:
1007
    if( asioIsInitialized )
1008
        {
1009
                ASIOExit();
1010
        }
1011

    
1012
    return result;
1013
}
1014

    
1015

    
1016
#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_     13   /* must be the same number of elements as in the array below */
1017
static ASIOSampleRate defaultSampleRateSearchOrder_[]
1018
     = {44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0,
1019
        192000.0, 16000.0, 12000.0, 11025.0, 9600.0, 8000.0 };
1020

    
1021

    
1022
static PaError InitPaDeviceInfoFromAsioDriver( PaAsioHostApiRepresentation *asioHostApi, 
1023
        const char *driverName, int driverIndex,
1024
        PaDeviceInfo *deviceInfo, PaAsioDeviceInfo *asioDeviceInfo )
1025
{
1026
    PaError result = paNoError;
1027

    
1028
    /* Due to the headless design of the ASIO API, drivers are free to write over data given to them (like M-Audio
1029
       drivers f.i.). This is an attempt to overcome that. */
1030
    union _tag_local {
1031
        PaAsioDriverInfo info;
1032
        char _padding[4096];
1033
    } paAsioDriver;
1034

    
1035
    asioDeviceInfo->asioChannelInfos = 0; /* we check this below to handle error cleanup */
1036

    
1037
    result = LoadAsioDriver( asioHostApi, driverName, &paAsioDriver.info, asioHostApi->systemSpecific );
1038
    if( result == paNoError )
1039
    {
1040
        PA_DEBUG(("PaAsio_Initialize: drv:%d name = %s\n",  driverIndex,deviceInfo->name));
1041
        PA_DEBUG(("PaAsio_Initialize: drv:%d inputChannels       = %d\n", driverIndex, paAsioDriver.info.inputChannelCount));
1042
        PA_DEBUG(("PaAsio_Initialize: drv:%d outputChannels      = %d\n", driverIndex, paAsioDriver.info.outputChannelCount));
1043
        PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMinSize       = %d\n", driverIndex, paAsioDriver.info.bufferMinSize));
1044
        PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMaxSize       = %d\n", driverIndex, paAsioDriver.info.bufferMaxSize));
1045
        PA_DEBUG(("PaAsio_Initialize: drv:%d bufferPreferredSize = %d\n", driverIndex, paAsioDriver.info.bufferPreferredSize));
1046
        PA_DEBUG(("PaAsio_Initialize: drv:%d bufferGranularity   = %d\n", driverIndex, paAsioDriver.info.bufferGranularity));
1047

    
1048
        deviceInfo->maxInputChannels  = paAsioDriver.info.inputChannelCount;
1049
        deviceInfo->maxOutputChannels = paAsioDriver.info.outputChannelCount;
1050

    
1051
        deviceInfo->defaultSampleRate = 0.;
1052
        bool foundDefaultSampleRate = false;
1053
        for( int j=0; j < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++j )
1054
        {
1055
            ASIOError asioError = ASIOCanSampleRate( defaultSampleRateSearchOrder_[j] );
1056
            if( asioError != ASE_NoClock && asioError != ASE_NotPresent )
1057
            {
1058
                deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[j];
1059
                foundDefaultSampleRate = true;
1060
                break;
1061
            }
1062
        }
1063

    
1064
        PA_DEBUG(("PaAsio_Initialize: drv:%d defaultSampleRate = %f\n", driverIndex, deviceInfo->defaultSampleRate));
1065

    
1066
        if( foundDefaultSampleRate ){
1067

    
1068
            /* calculate default latency values from bufferPreferredSize
1069
                for default low latency, and bufferMaxSize
1070
                for default high latency.
1071
                use the default sample rate to convert from samples to
1072
                seconds. Without knowing what sample rate the user will
1073
                use this is the best we can do.
1074
            */
1075

    
1076
            double defaultLowLatency =
1077
                    paAsioDriver.info.bufferPreferredSize / deviceInfo->defaultSampleRate;
1078

    
1079
            deviceInfo->defaultLowInputLatency = defaultLowLatency;
1080
            deviceInfo->defaultLowOutputLatency = defaultLowLatency;
1081

    
1082
            double defaultHighLatency =
1083
                    paAsioDriver.info.bufferMaxSize / deviceInfo->defaultSampleRate;
1084

    
1085
            if( defaultHighLatency < defaultLowLatency )
1086
                defaultHighLatency = defaultLowLatency; /* just in case the driver returns something strange */ 
1087
                    
1088
            deviceInfo->defaultHighInputLatency = defaultHighLatency;
1089
            deviceInfo->defaultHighOutputLatency = defaultHighLatency;
1090
            
1091
        }else{
1092

    
1093
            deviceInfo->defaultLowInputLatency = 0.;
1094
            deviceInfo->defaultLowOutputLatency = 0.;
1095
            deviceInfo->defaultHighInputLatency = 0.;
1096
            deviceInfo->defaultHighOutputLatency = 0.;
1097
        }
1098

    
1099
        PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowInputLatency = %f\n", driverIndex, deviceInfo->defaultLowInputLatency));
1100
        PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowOutputLatency = %f\n", driverIndex, deviceInfo->defaultLowOutputLatency));
1101
        PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighInputLatency = %f\n", driverIndex, deviceInfo->defaultHighInputLatency));
1102
        PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighOutputLatency = %f\n", driverIndex, deviceInfo->defaultHighOutputLatency));
1103

    
1104
        asioDeviceInfo->minBufferSize = paAsioDriver.info.bufferMinSize;
1105
        asioDeviceInfo->maxBufferSize = paAsioDriver.info.bufferMaxSize;
1106
        asioDeviceInfo->preferredBufferSize = paAsioDriver.info.bufferPreferredSize;
1107
        asioDeviceInfo->bufferGranularity = paAsioDriver.info.bufferGranularity;
1108

    
1109

    
1110
        asioDeviceInfo->asioChannelInfos = (ASIOChannelInfo*)PaUtil_GroupAllocateMemory(
1111
                asioHostApi->allocations,
1112
                sizeof(ASIOChannelInfo) * (deviceInfo->maxInputChannels
1113
                        + deviceInfo->maxOutputChannels) );
1114
        if( !asioDeviceInfo->asioChannelInfos )
1115
        {
1116
            result = paInsufficientMemory;
1117
            goto error_unload;
1118
        }
1119

    
1120
        int a;
1121

    
1122
        for( a=0; a < deviceInfo->maxInputChannels; ++a ){
1123
            asioDeviceInfo->asioChannelInfos[a].channel = a;
1124
            asioDeviceInfo->asioChannelInfos[a].isInput = ASIOTrue;
1125
            ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[a] );
1126
            if( asioError != ASE_OK )
1127
            {
1128
                result = paUnanticipatedHostError;
1129
                PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
1130
                goto error_unload;
1131
            }
1132
        }
1133

    
1134
        for( a=0; a < deviceInfo->maxOutputChannels; ++a ){
1135
            int b = deviceInfo->maxInputChannels + a;
1136
            asioDeviceInfo->asioChannelInfos[b].channel = a;
1137
            asioDeviceInfo->asioChannelInfos[b].isInput = ASIOFalse;
1138
            ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[b] );
1139
            if( asioError != ASE_OK )
1140
            {
1141
                result = paUnanticipatedHostError;
1142
                PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
1143
                goto error_unload;
1144
            }
1145
        }
1146

    
1147
        /* unload the driver */
1148
        UnloadAsioDriver();
1149
    }
1150

    
1151
    return result;
1152

    
1153
error_unload:
1154
    UnloadAsioDriver();
1155

    
1156
    if( asioDeviceInfo->asioChannelInfos ){
1157
        PaUtil_GroupFreeMemory( asioHostApi->allocations, asioDeviceInfo->asioChannelInfos );
1158
        asioDeviceInfo->asioChannelInfos = 0;
1159
    }
1160

    
1161
    return result;
1162
}
1163

    
1164

    
1165
/* we look up IsDebuggerPresent at runtime incase it isn't present (on Win95 for example) */
1166
typedef BOOL (WINAPI *IsDebuggerPresentPtr)(VOID);
1167
IsDebuggerPresentPtr IsDebuggerPresent_ = 0;
1168
//FARPROC IsDebuggerPresent_ = 0; // this is the current way to do it apparently according to davidv
1169

    
1170
PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
1171
{
1172
    PaError result = paNoError;
1173
    int i, driverCount;
1174
    PaAsioHostApiRepresentation *asioHostApi;
1175
    PaAsioDeviceInfo *deviceInfoArray;
1176
    char **names;
1177
    asioHostApi = (PaAsioHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaAsioHostApiRepresentation) );
1178
    if( !asioHostApi )
1179
    {
1180
        result = paInsufficientMemory;
1181
        goto error;
1182
    }
1183

    
1184
    memset( asioHostApi, 0, sizeof(PaAsioHostApiRepresentation) ); /* ensure all fields are zeroed. especially asioHostApi->allocations */
1185

    
1186
    /*
1187
        We initialize COM ourselves here and uninitialize it in Terminate().
1188
        This should be the only COM initialization needed in this module.
1189

1190
        The ASIO SDK may also initialize COM but since we want to reduce dependency
1191
        on the ASIO SDK we manage COM initialization ourselves.
1192

1193
        There used to be code that initialized COM in other situations
1194
        such as when creating a Stream. This made PA work when calling Pa_CreateStream
1195
        from a non-main thread. However we currently consider initialization 
1196
        of COM in non-main threads to be the caller's responsibility.
1197
    */
1198
    result = PaWinUtil_CoInitialize( paASIO, &asioHostApi->comInitializationResult );
1199
    if( result != paNoError )
1200
    {
1201
        goto error;
1202
    }
1203

    
1204
    asioHostApi->asioDrivers = 0; /* avoid surprises in our error handler below */
1205

    
1206
    asioHostApi->allocations = PaUtil_CreateAllocationGroup();
1207
    if( !asioHostApi->allocations )
1208
    {
1209
        result = paInsufficientMemory;
1210
        goto error;
1211
    }
1212

    
1213
    /* Allocate the AsioDrivers() driver list (class from ASIO SDK) */
1214
    try
1215
    {
1216
        asioHostApi->asioDrivers = new AsioDrivers(); /* invokes CoInitialize(0) in AsioDriverList::AsioDriverList */
1217
    } 
1218
    catch (std::bad_alloc)
1219
    {
1220
        asioHostApi->asioDrivers = 0;
1221
    }
1222
    /* some implementations of new (ie MSVC, see http://support.microsoft.com/?kbid=167733)
1223
       don't throw std::bad_alloc, so we also explicitly test for a null return. */
1224
    if( asioHostApi->asioDrivers == 0 )
1225
    {
1226
        result = paInsufficientMemory;
1227
        goto error;
1228
    }
1229

    
1230
    asioDrivers = asioHostApi->asioDrivers; /* keep SDK global in sync until we stop depending on it */
1231

    
1232
    asioHostApi->systemSpecific = 0;
1233
    asioHostApi->openAsioDeviceIndex = paNoDevice;
1234

    
1235
    *hostApi = &asioHostApi->inheritedHostApiRep;
1236
    (*hostApi)->info.structVersion = 1;
1237

    
1238
    (*hostApi)->info.type = paASIO;
1239
    (*hostApi)->info.name = "ASIO";
1240
    (*hostApi)->info.deviceCount = 0;
1241

    
1242
    #ifdef WINDOWS
1243
        /* use desktop window as system specific ptr */
1244
        asioHostApi->systemSpecific = GetDesktopWindow();
1245
    #endif
1246

    
1247
    /* driverCount is the number of installed drivers - not necessarily
1248
        the number of installed physical devices. */
1249
    #if MAC
1250
        driverCount = asioHostApi->asioDrivers->getNumFragments();
1251
    #elif WINDOWS
1252
        driverCount = asioHostApi->asioDrivers->asioGetNumDev();
1253
    #endif
1254

    
1255
    if( driverCount > 0 )
1256
    {
1257
        names = GetAsioDriverNames( asioHostApi, asioHostApi->allocations, driverCount );
1258
        if( !names )
1259
        {
1260
            result = paInsufficientMemory;
1261
            goto error;
1262
        }
1263

    
1264

    
1265
        /* allocate enough space for all drivers, even if some aren't installed */
1266

    
1267
        (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
1268
                asioHostApi->allocations, sizeof(PaDeviceInfo*) * driverCount );
1269
        if( !(*hostApi)->deviceInfos )
1270
        {
1271
            result = paInsufficientMemory;
1272
            goto error;
1273
        }
1274

    
1275
        /* allocate all device info structs in a contiguous block */
1276
        deviceInfoArray = (PaAsioDeviceInfo*)PaUtil_GroupAllocateMemory(
1277
                asioHostApi->allocations, sizeof(PaAsioDeviceInfo) * driverCount );
1278
        if( !deviceInfoArray )
1279
        {
1280
            result = paInsufficientMemory;
1281
            goto error;
1282
        }
1283

    
1284
        IsDebuggerPresent_ = (IsDebuggerPresentPtr)GetProcAddress( LoadLibraryA( "Kernel32.dll" ), "IsDebuggerPresent" );
1285

    
1286
        for( i=0; i < driverCount; ++i )
1287
        {
1288
            PA_DEBUG(("ASIO names[%d]:%s\n",i,names[i]));
1289

    
1290
            // Since portaudio opens ALL ASIO drivers, and no one else does that,
1291
            // we face fact that some drivers were not meant for it, drivers which act
1292
            // like shells on top of REAL drivers, for instance.
1293
            // so we get duplicate handles, locks and other problems.
1294
            // so lets NOT try to load any such wrappers. 
1295
            // The ones i [davidv] know of so far are:
1296

    
1297
            if (   strcmp (names[i],"ASIO DirectX Full Duplex Driver") == 0
1298
                || strcmp (names[i],"ASIO Multimedia Driver")          == 0
1299
                || strncmp(names[i],"Premiere",8)                      == 0   //"Premiere Elements Windows Sound 1.0"
1300
                || strncmp(names[i],"Adobe",5)                         == 0   //"Adobe Default Windows Sound 1.5"
1301
               )
1302
            {
1303
                PA_DEBUG(("BLACKLISTED!!!\n"));
1304
                continue;
1305
            }
1306

    
1307

    
1308
            if( IsDebuggerPresent_ && IsDebuggerPresent_() )  
1309
            {
1310
                /* ASIO Digidesign Driver uses PACE copy protection which quits out
1311
                   if a debugger is running. So we don't load it if a debugger is running. */
1312
                if( strcmp(names[i], "ASIO Digidesign Driver") == 0 )  
1313
                {
1314
                    PA_DEBUG(("BLACKLISTED!!! ASIO Digidesign Driver would quit the debugger\n"));  
1315
                    continue;
1316
                }  
1317
            }  
1318

    
1319

    
1320
            /* Attempt to init device info from the asio driver... */
1321
            {
1322
                PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
1323
                PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo;
1324

    
1325
                deviceInfo->structVersion = 2;
1326
                deviceInfo->hostApi = hostApiIndex;
1327

    
1328
                deviceInfo->name = names[i];
1329

    
1330
                if( InitPaDeviceInfoFromAsioDriver( asioHostApi, names[i], i, deviceInfo, asioDeviceInfo ) == paNoError )
1331
                {
1332
                    (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
1333
                    ++(*hostApi)->info.deviceCount;
1334
                }
1335
                                else
1336
                                {
1337
                    PA_DEBUG(("Skipping ASIO device:%s\n",names[i]));
1338
                    continue;
1339
                }
1340
            }
1341
        }
1342
    }
1343

    
1344
    if( (*hostApi)->info.deviceCount > 0 )
1345
    {
1346
        (*hostApi)->info.defaultInputDevice = 0;
1347
        (*hostApi)->info.defaultOutputDevice = 0;
1348
    }
1349
    else
1350
    {
1351
        (*hostApi)->info.defaultInputDevice = paNoDevice;
1352
        (*hostApi)->info.defaultOutputDevice = paNoDevice;
1353
    }
1354

    
1355

    
1356
    (*hostApi)->Terminate = Terminate;
1357
    (*hostApi)->OpenStream = OpenStream;
1358
    (*hostApi)->IsFormatSupported = IsFormatSupported;
1359

    
1360
    PaUtil_InitializeStreamInterface( &asioHostApi->callbackStreamInterface, CloseStream, StartStream,
1361
                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
1362
                                      GetStreamTime, GetStreamCpuLoad,
1363
                                      PaUtil_DummyRead, PaUtil_DummyWrite,
1364
                                      PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
1365

    
1366
    PaUtil_InitializeStreamInterface( &asioHostApi->blockingStreamInterface, CloseStream, StartStream,
1367
                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
1368
                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
1369
                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
1370

    
1371
    return result;
1372

    
1373
error:
1374
    if( asioHostApi )
1375
    {
1376
        if( asioHostApi->allocations )
1377
        {
1378
            PaUtil_FreeAllAllocations( asioHostApi->allocations );
1379
            PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
1380
        }
1381

    
1382
        delete asioHostApi->asioDrivers;
1383
        asioDrivers = 0; /* keep SDK global in sync until we stop depending on it */
1384

    
1385
        PaWinUtil_CoUninitialize( paASIO, &asioHostApi->comInitializationResult );
1386

    
1387
        PaUtil_FreeMemory( asioHostApi );
1388
    }
1389

    
1390
    return result;
1391
}
1392

    
1393

    
1394
static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
1395
{
1396
    PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
1397

    
1398
    /*
1399
        IMPLEMENT ME:
1400
            - clean up any resources not handled by the allocation group (need to review if there are any)
1401
    */
1402

    
1403
    if( asioHostApi->allocations )
1404
    {
1405
        PaUtil_FreeAllAllocations( asioHostApi->allocations );
1406
        PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
1407
    }
1408

    
1409
    delete asioHostApi->asioDrivers;
1410
    asioDrivers = 0; /* keep SDK global in sync until we stop depending on it */
1411

    
1412
    PaWinUtil_CoUninitialize( paASIO, &asioHostApi->comInitializationResult );
1413

    
1414
    PaUtil_FreeMemory( asioHostApi );
1415
}
1416

    
1417

    
1418
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
1419
                                  const PaStreamParameters *inputParameters,
1420
                                  const PaStreamParameters *outputParameters,
1421
                                  double sampleRate )
1422
{
1423
    PaError result = paNoError;
1424
    PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
1425
    PaAsioDriverInfo *driverInfo = &asioHostApi->openAsioDriverInfo;
1426
    int inputChannelCount, outputChannelCount;
1427
    PaSampleFormat inputSampleFormat, outputSampleFormat;
1428
    PaDeviceIndex asioDeviceIndex;                                  
1429
    ASIOError asioError;
1430
    
1431
    if( inputParameters && outputParameters )
1432
    {
1433
        /* full duplex ASIO stream must use the same device for input and output */
1434

    
1435
        if( inputParameters->device != outputParameters->device )
1436
            return paBadIODeviceCombination;
1437
    }
1438
    
1439
    if( inputParameters )
1440
    {
1441
        inputChannelCount = inputParameters->channelCount;
1442
        inputSampleFormat = inputParameters->sampleFormat;
1443

    
1444
        /* all standard sample formats are supported by the buffer adapter,
1445
            this implementation doesn't support any custom sample formats */
1446
        if( inputSampleFormat & paCustomFormat )
1447
            return paSampleFormatNotSupported;
1448
            
1449
        /* unless alternate device specification is supported, reject the use of
1450
            paUseHostApiSpecificDeviceSpecification */
1451

    
1452
        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
1453
            return paInvalidDevice;
1454

    
1455
        asioDeviceIndex = inputParameters->device;
1456

    
1457
        /* validate inputStreamInfo */
1458
        /** @todo do more validation here */
1459
        // if( inputParameters->hostApiSpecificStreamInfo )
1460
        //    return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
1461
    }
1462
    else
1463
    {
1464
        inputChannelCount = 0;
1465
    }
1466

    
1467
    if( outputParameters )
1468
    {
1469
        outputChannelCount = outputParameters->channelCount;
1470
        outputSampleFormat = outputParameters->sampleFormat;
1471

    
1472
        /* all standard sample formats are supported by the buffer adapter,
1473
            this implementation doesn't support any custom sample formats */
1474
        if( outputSampleFormat & paCustomFormat )
1475
            return paSampleFormatNotSupported;
1476
            
1477
        /* unless alternate device specification is supported, reject the use of
1478
            paUseHostApiSpecificDeviceSpecification */
1479

    
1480
        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
1481
            return paInvalidDevice;
1482

    
1483
        asioDeviceIndex = outputParameters->device;
1484

    
1485
        /* validate outputStreamInfo */
1486
        /** @todo do more validation here */
1487
        // if( outputParameters->hostApiSpecificStreamInfo )
1488
        //    return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
1489
    }
1490
    else
1491
    {
1492
        outputChannelCount = 0;
1493
    }
1494

    
1495

    
1496

    
1497
    /* if an ASIO device is open we can only get format information for the currently open device */
1498

    
1499
    if( asioHostApi->openAsioDeviceIndex != paNoDevice 
1500
            && asioHostApi->openAsioDeviceIndex != asioDeviceIndex )
1501
    {
1502
        return paDeviceUnavailable;
1503
    }
1504

    
1505

    
1506
    /* NOTE: we load the driver and use its current settings
1507
        rather than the ones in our device info structure which may be stale */
1508

    
1509
    /* open the device if it's not already open */
1510
    if( asioHostApi->openAsioDeviceIndex == paNoDevice )
1511
    {
1512
        result = LoadAsioDriver( asioHostApi, asioHostApi->inheritedHostApiRep.deviceInfos[ asioDeviceIndex ]->name,
1513
                driverInfo, asioHostApi->systemSpecific );
1514
        if( result != paNoError )
1515
            return result;
1516
    }
1517

    
1518
    /* check that input device can support inputChannelCount */
1519
    if( inputChannelCount > 0 )
1520
    {
1521
        if( inputChannelCount > driverInfo->inputChannelCount )
1522
        {
1523
            result = paInvalidChannelCount;
1524
            goto done;
1525
        }
1526
    }
1527

    
1528
    /* check that output device can support outputChannelCount */
1529
    if( outputChannelCount )
1530
    {
1531
        if( outputChannelCount > driverInfo->outputChannelCount )
1532
        {
1533
            result = paInvalidChannelCount;
1534
            goto done;
1535
        }
1536
    }
1537
    
1538
    /* query for sample rate support */
1539
    asioError = ASIOCanSampleRate( sampleRate );
1540
    if( asioError == ASE_NoClock || asioError == ASE_NotPresent )
1541
    {
1542
        result = paInvalidSampleRate;
1543
        goto done;
1544
    }
1545

    
1546
done:
1547
    /* close the device if it wasn't already open */
1548
    if( asioHostApi->openAsioDeviceIndex == paNoDevice )
1549
    {
1550
        UnloadAsioDriver(); /* not sure if we should check for errors here */
1551
    }
1552

    
1553
    if( result == paNoError )
1554
        return paFormatIsSupported;
1555
    else
1556
        return result;
1557
}
1558

    
1559

    
1560

    
1561
/** A data structure specifically for storing blocking i/o related data. */
1562
typedef struct PaAsioStreamBlockingState
1563
{
1564
    int stopFlag; /**< Flag indicating that block processing is to be stopped. */
1565

    
1566
    unsigned long writeBuffersRequested; /**< The number of available output buffers, requested by the #WriteStream() function. */
1567
    unsigned long readFramesRequested;   /**< The number of available input frames, requested by the #ReadStream() function. */
1568

    
1569
    int writeBuffersRequestedFlag; /**< Flag to indicate that #WriteStream() has requested more output buffers to be available. */
1570
    int readFramesRequestedFlag;   /**< Flag to indicate that #ReadStream() requires more input frames to be available. */
1571

    
1572
    HANDLE writeBuffersReadyEvent; /**< Event to signal that requested output buffers are available. */
1573
    HANDLE readFramesReadyEvent;   /**< Event to signal that requested input frames are available. */
1574

    
1575
    void *writeRingBufferData; /**< The actual ring buffer memory, used by the output ring buffer. */
1576
    void *readRingBufferData;  /**< The actual ring buffer memory, used by the input ring buffer. */
1577

    
1578
    PaUtilRingBuffer writeRingBuffer; /**< Frame-aligned blocking i/o ring buffer to store output data (interleaved user format). */
1579
    PaUtilRingBuffer readRingBuffer;  /**< Frame-aligned blocking i/o ring buffer to store input data (interleaved user format). */
1580

    
1581
    long writeRingBufferInitialFrames; /**< The initial number of silent frames within the output ring buffer. */
1582

    
1583
    const void **writeStreamBuffer; /**< Temp buffer, used by #WriteStream() for handling non-interleaved data. */
1584
    void **readStreamBuffer; /**< Temp buffer, used by #ReadStream() for handling non-interleaved data. */
1585

    
1586
    PaUtilBufferProcessor bufferProcessor; /**< Buffer processor, used to handle the blocking i/o ring buffers. */
1587

    
1588
    int outputUnderflowFlag; /**< Flag to signal an output underflow from within the callback function. */
1589
    int inputOverflowFlag; /**< Flag to signal an input overflow from within the callback function. */
1590
}
1591
PaAsioStreamBlockingState;
1592

    
1593

    
1594

    
1595
/* PaAsioStream - a stream data structure specifically for this implementation */
1596

    
1597
typedef struct PaAsioStream
1598
{
1599
    PaUtilStreamRepresentation streamRepresentation;
1600
    PaUtilCpuLoadMeasurer cpuLoadMeasurer;
1601
    PaUtilBufferProcessor bufferProcessor;
1602

    
1603
    PaAsioHostApiRepresentation *asioHostApi;
1604
    unsigned long framesPerHostCallback;
1605

    
1606
    /* ASIO driver info  - these may not be needed for the life of the stream,
1607
        but store them here until we work out how format conversion is going
1608
        to work. */
1609

    
1610
    ASIOBufferInfo *asioBufferInfos;
1611
    ASIOChannelInfo *asioChannelInfos;
1612
    long asioInputLatencyFrames, asioOutputLatencyFrames; // actual latencies returned by asio
1613

    
1614
    long inputChannelCount, outputChannelCount;
1615
    bool postOutput;
1616

    
1617
    void **bufferPtrs; /* this is carved up for inputBufferPtrs and outputBufferPtrs */
1618
    void **inputBufferPtrs[2];
1619
    void **outputBufferPtrs[2];
1620

    
1621
    PaAsioBufferConverter *inputBufferConverter;
1622
    long inputShift;
1623
    PaAsioBufferConverter *outputBufferConverter;
1624
    long outputShift;
1625

    
1626
    volatile bool stopProcessing;
1627
    int stopPlayoutCount;
1628
    HANDLE completedBuffersPlayedEvent;
1629

    
1630
    bool streamFinishedCallbackCalled;
1631
    int isStopped;
1632
    volatile int isActive;
1633
    volatile bool zeroOutput; /* all future calls to the callback will output silence */
1634

    
1635
    volatile long reenterCount;
1636
    volatile long reenterError;
1637

    
1638
    PaStreamCallbackFlags callbackFlags;
1639

    
1640
    PaAsioStreamBlockingState *blockingState; /**< Blocking i/o data struct, or NULL when using callback interface. */
1641
}
1642
PaAsioStream;
1643

    
1644
static PaAsioStream *theAsioStream = 0; /* due to ASIO sdk limitations there can be only one stream */
1645

    
1646

    
1647
static void ZeroOutputBuffers( PaAsioStream *stream, long index )
1648
{
1649
    int i;
1650

    
1651
    for( i=0; i < stream->outputChannelCount; ++i )
1652
    {
1653
        void *buffer = stream->asioBufferInfos[ i + stream->inputChannelCount ].buffers[index];
1654

    
1655
        int bytesPerSample = BytesPerAsioSample( stream->asioChannelInfos[ i + stream->inputChannelCount ].type );
1656

    
1657
        memset( buffer, 0, stream->framesPerHostCallback * bytesPerSample );
1658
    }
1659
}
1660

    
1661

    
1662
/* return the next power of two >= x. 
1663
   Returns the input parameter if it is already a power of two. 
1664
   http://stackoverflow.com/questions/364985/algorithm-for-finding-the-smallest-power-of-two-thats-greater-or-equal-to-a-giv 
1665
*/
1666
static unsigned long NextPowerOfTwo( unsigned long x )
1667
{
1668
    --x;
1669
    x |= x >> 1;
1670
    x |= x >> 2;
1671
    x |= x >> 4;
1672
    x |= x >> 8;
1673
    x |= x >> 16;
1674
    /* If you needed to deal with numbers > 2^32 the following would be needed. 
1675
       For latencies, we don't deal with values this large. 
1676
     x |= x >> 16;
1677
    */
1678

    
1679
    return x + 1;
1680
}
1681

    
1682

    
1683
static unsigned long SelectHostBufferSizeForUnspecifiedUserFramesPerBuffer( 
1684
        unsigned long targetBufferingLatencyFrames, PaAsioDriverInfo *driverInfo )
1685
{
1686
        /* Choose a host buffer size based only on targetBufferingLatencyFrames and the 
1687
           device's supported buffer sizes. Always returns a valid value.
1688
        */
1689

    
1690
        unsigned long result;
1691

    
1692
        if( targetBufferingLatencyFrames <= (unsigned long)driverInfo->bufferMinSize )
1693
    {
1694
        result = driverInfo->bufferMinSize;
1695
    }
1696
    else if( targetBufferingLatencyFrames >= (unsigned long)driverInfo->bufferMaxSize )
1697
    {
1698
        result = driverInfo->bufferMaxSize;
1699
    }
1700
    else
1701
    {
1702
                if( driverInfo->bufferGranularity == 0 ) /* single fixed host buffer size */
1703
        {
1704
            /* The documentation states that bufferGranularity should be zero 
1705
               when bufferMinSize, bufferMaxSize and bufferPreferredSize are the 
1706
               same. We assume that is the case.
1707
            */
1708

    
1709
            result = driverInfo->bufferPreferredSize;
1710
        }
1711
                else if( driverInfo->bufferGranularity == -1 ) /* power-of-two */
1712
        {
1713
                    /* We assume bufferMinSize and bufferMaxSize are powers of two. */
1714

    
1715
            result = NextPowerOfTwo( targetBufferingLatencyFrames );
1716

    
1717
            if( result < (unsigned long)driverInfo->bufferMinSize )
1718
                result = driverInfo->bufferMinSize;
1719

    
1720
            if( result > (unsigned long)driverInfo->bufferMaxSize )
1721
                result = driverInfo->bufferMaxSize;
1722
        }
1723
        else /* modulo bufferGranularity */
1724
        {
1725
            /* round up to the next multiple of granularity */
1726
            unsigned long n = (targetBufferingLatencyFrames + driverInfo->bufferGranularity - 1) 
1727
                    / driverInfo->bufferGranularity;
1728
            
1729
            result = n * driverInfo->bufferGranularity;
1730

    
1731
            if( result < (unsigned long)driverInfo->bufferMinSize )
1732
                result = driverInfo->bufferMinSize;
1733

    
1734
            if( result > (unsigned long)driverInfo->bufferMaxSize )
1735
                result = driverInfo->bufferMaxSize;
1736
        }
1737
    }
1738

    
1739
        return result;
1740
}
1741

    
1742

    
1743
static unsigned long SelectHostBufferSizeForSpecifiedUserFramesPerBuffer( 
1744
        unsigned long targetBufferingLatencyFrames, unsigned long userFramesPerBuffer,
1745
        PaAsioDriverInfo *driverInfo )
1746
{
1747
        /* Select a host buffer size conforming to targetBufferingLatencyFrames 
1748
           and the device's supported buffer sizes.
1749
           The return value will always be a multiple of userFramesPerBuffer. 
1750
           If a valid buffer size can not be found the function returns 0.
1751

1752
           The current implementation uses a simple iterative search for clarity.
1753
           Feel free to suggest a closed form solution.
1754
        */
1755
        unsigned long result = 0;
1756

    
1757
        assert( userFramesPerBuffer != 0 );
1758
        
1759
        if( driverInfo->bufferGranularity == 0 ) /* single fixed host buffer size */
1760
    {
1761
        /* The documentation states that bufferGranularity should be zero 
1762
           when bufferMinSize, bufferMaxSize and bufferPreferredSize are the 
1763
           same. We assume that is the case.
1764
        */
1765

    
1766
                if( (driverInfo->bufferPreferredSize % userFramesPerBuffer) == 0 )
1767
                        result = driverInfo->bufferPreferredSize;
1768
    }
1769
        else if( driverInfo->bufferGranularity == -1 ) /* power-of-two */
1770
    {
1771
                /* We assume bufferMinSize and bufferMaxSize are powers of two. */
1772

    
1773
        /* Search all powers of two in the range [bufferMinSize,bufferMaxSize] 
1774
           for multiples of userFramesPerBuffer. We prefer the first multiple
1775
           that is equal or greater than targetBufferingLatencyFrames, or  
1776
           failing that, the largest multiple less than 
1777
           targetBufferingLatencyFrames.
1778
        */
1779
        unsigned long x = (unsigned long)driverInfo->bufferMinSize; 
1780
                do {
1781
                        if( (x % userFramesPerBuffer) == 0 )
1782
                        {
1783
                /* any multiple of userFramesPerBuffer is acceptable */
1784
                                result = x;
1785
                                if( result >= targetBufferingLatencyFrames )
1786
                                        break; /* stop. a value >= to targetBufferingLatencyFrames is ideal. */
1787
                        }
1788

    
1789
                        x *= 2;
1790
                } while( x <= (unsigned long)driverInfo->bufferMaxSize );
1791
    }
1792
    else /* modulo granularity */
1793
    {
1794
                /* We assume bufferMinSize is a multiple of bufferGranularity. */
1795

    
1796
        /* Search all multiples of bufferGranularity in the range 
1797
           [bufferMinSize,bufferMaxSize] for multiples of userFramesPerBuffer. 
1798
           We prefer the first multiple that is equal or greater than 
1799
           targetBufferingLatencyFrames, or failing that, the largest multiple  
1800
           less than targetBufferingLatencyFrames.
1801
        */
1802
                unsigned long x = (unsigned long)driverInfo->bufferMinSize; 
1803
                do {
1804
                        if( (x % userFramesPerBuffer) == 0 )
1805
                        {
1806
                /* any multiple of userFramesPerBuffer is acceptable */
1807
                                result = x;
1808
                                if( result >= targetBufferingLatencyFrames )
1809
                                        break; /* stop. a value >= to targetBufferingLatencyFrames is ideal. */
1810
                        }
1811

    
1812
                        x += driverInfo->bufferGranularity;
1813
                } while( x <= (unsigned long)driverInfo->bufferMaxSize );
1814
    }
1815

    
1816
        return result;
1817
}
1818

    
1819

    
1820
static unsigned long SelectHostBufferSize( 
1821
        unsigned long targetBufferingLatencyFrames, 
1822
        unsigned long userFramesPerBuffer, PaAsioDriverInfo *driverInfo )
1823
{
1824
    unsigned long result = 0;
1825

    
1826
    /* We select a host buffer size based on the following requirements 
1827
       (in priority order):
1828

1829
        1. The host buffer size must be permissible according to the ASIO 
1830
           driverInfo buffer size constraints (min, max, granularity or 
1831
           powers-of-two).
1832

1833
        2. If the user specifies a non-zero framesPerBuffer parameter 
1834
           (userFramesPerBuffer here) the host buffer should be a multiple of 
1835
           this (subject to the constraints in (1) above).
1836

1837
           [NOTE: Where no permissible host buffer size is a multiple of 
1838
           userFramesPerBuffer, we choose a value as if userFramesPerBuffer were 
1839
           zero (i.e. we ignore it). This strategy is open for review ~ perhaps 
1840
           there are still "more optimal" buffer sizes related to 
1841
           userFramesPerBuffer that we could use.]
1842

1843
        3. The host buffer size should be greater than or equal to 
1844
           targetBufferingLatencyFrames, subject to (1) and (2) above. Where it 
1845
           is not possible to select a host buffer size equal or greater than 
1846
           targetBufferingLatencyFrames, the highest buffer size conforming to  
1847
           (1) and (2) should be chosen.
1848
    */
1849

    
1850
        if( userFramesPerBuffer != 0 )
1851
        {
1852
                /* userFramesPerBuffer is specified, try to find a buffer size that's 
1853
           a multiple of it */
1854
                result = SelectHostBufferSizeForSpecifiedUserFramesPerBuffer( 
1855
                targetBufferingLatencyFrames, userFramesPerBuffer, driverInfo );
1856
        }
1857

    
1858
        if( result == 0 )
1859
        {
1860
                /* either userFramesPerBuffer was not specified, or we couldn't find a 
1861
           host buffer size that is a multiple of it. Select a host buffer size 
1862
           according to targetBufferingLatencyFrames and the ASIO driverInfo 
1863
           buffer size constraints.
1864
             */
1865
                result = SelectHostBufferSizeForUnspecifiedUserFramesPerBuffer( 
1866
                targetBufferingLatencyFrames, driverInfo );
1867
        }
1868

    
1869
        return result;
1870
}
1871

    
1872

    
1873
/* returns channelSelectors if present */
1874

    
1875
static PaError ValidateAsioSpecificStreamInfo(
1876
        const PaStreamParameters *streamParameters,
1877
        const PaAsioStreamInfo *streamInfo,
1878
        int deviceChannelCount,
1879
        int **channelSelectors )
1880
{
1881
    if( streamInfo )
1882
    {
1883
        if( streamInfo->size != sizeof( PaAsioStreamInfo )
1884
                || streamInfo->version != 1 )
1885
        {
1886
            return paIncompatibleHostApiSpecificStreamInfo;
1887
        }
1888

    
1889
        if( streamInfo->flags & paAsioUseChannelSelectors )
1890
            *channelSelectors = streamInfo->channelSelectors;
1891

    
1892
        if( !(*channelSelectors) )
1893
            return paIncompatibleHostApiSpecificStreamInfo;
1894

    
1895
        for( int i=0; i < streamParameters->channelCount; ++i ){
1896
             if( (*channelSelectors)[i] < 0
1897
                    || (*channelSelectors)[i] >= deviceChannelCount ){
1898
                return paInvalidChannelCount;
1899
             }           
1900
        }
1901
    }
1902

    
1903
    return paNoError;
1904
}
1905

    
1906

    
1907
static bool IsUsingExternalClockSource()
1908
{
1909
    bool result = false;
1910
    ASIOError asioError;
1911
    ASIOClockSource clocks[32];
1912
    long numSources=32;
1913

    
1914
    /* davidv: listing ASIO Clock sources. there is an ongoing investigation by
1915
       me about whether or not to call ASIOSetSampleRate if an external Clock is
1916
       used. A few drivers expected different things here */
1917
    
1918
    asioError = ASIOGetClockSources(clocks, &numSources);
1919
    if( asioError != ASE_OK ){
1920
        PA_DEBUG(("ERROR: ASIOGetClockSources: %s\n", PaAsio_GetAsioErrorText(asioError) ));
1921
    }else{
1922
        PA_DEBUG(("INFO ASIOGetClockSources listing %d clocks\n", numSources ));
1923
        for (int i=0;i<numSources;++i){
1924
            PA_DEBUG(("ASIOClockSource%d %s current:%d\n", i, clocks[i].name, clocks[i].isCurrentSource ));
1925
           
1926
            if (clocks[i].isCurrentSource)
1927
                result = true;
1928
        }
1929
    }
1930

    
1931
    return result;
1932
}
1933

    
1934

    
1935
static PaError ValidateAndSetSampleRate( double sampleRate )
1936
{
1937
    PaError result = paNoError;
1938
    ASIOError asioError;
1939

    
1940
    // check that the device supports the requested sample rate 
1941

    
1942
    asioError = ASIOCanSampleRate( sampleRate );
1943
    PA_DEBUG(("ASIOCanSampleRate(%f):%d\n", sampleRate, asioError ));
1944

    
1945
    if( asioError != ASE_OK )
1946
    {
1947
        result = paInvalidSampleRate;
1948
        PA_DEBUG(("ERROR: ASIOCanSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
1949
        goto error;
1950
    }
1951

    
1952
    // retrieve the current sample rate, we only change to the requested
1953
    // sample rate if the device is not already in that rate.
1954

    
1955
    ASIOSampleRate oldRate;
1956
    asioError = ASIOGetSampleRate(&oldRate);
1957
    if( asioError != ASE_OK )
1958
    {
1959
        result = paInvalidSampleRate;
1960
        PA_DEBUG(("ERROR: ASIOGetSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
1961
        goto error;
1962
    }
1963
    PA_DEBUG(("ASIOGetSampleRate:%f\n",oldRate));
1964

    
1965
    if (oldRate != sampleRate){
1966
        /* Set sample rate */
1967

    
1968
        PA_DEBUG(("before ASIOSetSampleRate(%f)\n",sampleRate));
1969

    
1970
        /*
1971
            If you have problems with some drivers when externally clocked, 
1972
            try switching on the following line and commenting out the one after it.
1973
            See IsUsingExternalClockSource() for more info.
1974
        */
1975
        //if( IsUsingExternalClockSource() ){
1976
        if( false ){
1977
            asioError = ASIOSetSampleRate( 0 );
1978
        }else{
1979
            asioError = ASIOSetSampleRate( sampleRate );
1980
        }
1981
        if( asioError != ASE_OK )
1982
        {
1983
            result = paInvalidSampleRate;
1984
            PA_DEBUG(("ERROR: ASIOSetSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
1985
            goto error;
1986
        }
1987
        PA_DEBUG(("after ASIOSetSampleRate(%f)\n",sampleRate));
1988
    }
1989
    else
1990
    {
1991
        PA_DEBUG(("No Need to change SR\n"));
1992
    }
1993

    
1994
error:
1995
    return result;
1996
}
1997

    
1998

    
1999
/* see pa_hostapi.h for a list of validity guarantees made about OpenStream  parameters */
2000

    
2001
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
2002
                           PaStream** s,
2003
                           const PaStreamParameters *inputParameters,
2004
                           const PaStreamParameters *outputParameters,
2005
                           double sampleRate,
2006
                           unsigned long framesPerBuffer,
2007
                           PaStreamFlags streamFlags,
2008
                           PaStreamCallback *streamCallback,
2009
                           void *userData )
2010
{
2011
    PaError result = paNoError;
2012
    PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
2013
    PaAsioStream *stream = 0;
2014
    PaAsioStreamInfo *inputStreamInfo, *outputStreamInfo;
2015
    unsigned long framesPerHostBuffer;
2016
    int inputChannelCount, outputChannelCount;
2017
    PaSampleFormat inputSampleFormat, outputSampleFormat;
2018
    PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
2019
    unsigned long suggestedInputLatencyFrames;
2020
    unsigned long suggestedOutputLatencyFrames;
2021
    PaDeviceIndex asioDeviceIndex;
2022
    ASIOError asioError;
2023
    int asioIsInitialized = 0;
2024
    int asioBuffersCreated = 0;
2025
    int completedBuffersPlayedEventInited = 0;
2026
    int i;
2027
    PaAsioDriverInfo *driverInfo;
2028
    int *inputChannelSelectors = 0;
2029
    int *outputChannelSelectors = 0;
2030

    
2031
    /* Are we using blocking i/o interface? */
2032
    int usingBlockingIo = ( !streamCallback ) ? TRUE : FALSE;
2033
    /* Blocking i/o stuff */
2034
    long lBlockingBufferSize     = 0; /* Desired ring buffer size in samples. */
2035
    long lBlockingBufferSizePow2 = 0; /* Power-of-2 rounded ring buffer size. */
2036
    long lBytesPerFrame          = 0; /* Number of bytes per input/output frame. */
2037
    int blockingWriteBuffersReadyEventInitialized = 0; /* Event init flag. */
2038
    int blockingReadFramesReadyEventInitialized   = 0; /* Event init flag. */
2039

    
2040
    int callbackBufferProcessorInited = FALSE;
2041
    int blockingBufferProcessorInited = FALSE;
2042

    
2043
    /* unless we move to using lower level ASIO calls, we can only have
2044
        one device open at a time */
2045
    if( asioHostApi->openAsioDeviceIndex != paNoDevice )
2046
    {
2047
        PA_DEBUG(("OpenStream paDeviceUnavailable\n"));
2048
        return paDeviceUnavailable;
2049
    }
2050

    
2051
    assert( theAsioStream == 0 );
2052

    
2053
    if( inputParameters && outputParameters )
2054
    {
2055
        /* full duplex ASIO stream must use the same device for input and output */
2056

    
2057
        if( inputParameters->device != outputParameters->device )
2058
        {
2059
            PA_DEBUG(("OpenStream paBadIODeviceCombination\n"));
2060
            return paBadIODeviceCombination;
2061
        }
2062
    }
2063

    
2064
    if( inputParameters )
2065
    {
2066
        inputChannelCount = inputParameters->channelCount;
2067
        inputSampleFormat = inputParameters->sampleFormat;
2068
        suggestedInputLatencyFrames = (unsigned long)((inputParameters->suggestedLatency * sampleRate)+0.5f);
2069

    
2070
        /* unless alternate device specification is supported, reject the use of
2071
            paUseHostApiSpecificDeviceSpecification */
2072
        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
2073
            return paInvalidDevice;
2074

    
2075
        asioDeviceIndex = inputParameters->device;
2076

    
2077
        PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[asioDeviceIndex];
2078

    
2079
        /* validate hostApiSpecificStreamInfo */
2080
        inputStreamInfo = (PaAsioStreamInfo*)inputParameters->hostApiSpecificStreamInfo;
2081
        result = ValidateAsioSpecificStreamInfo( inputParameters, inputStreamInfo,
2082
            asioDeviceInfo->commonDeviceInfo.maxInputChannels,
2083
            &inputChannelSelectors
2084
        );
2085
        if( result != paNoError ) return result;
2086
    }
2087
    else
2088
    {
2089
        inputChannelCount = 0;
2090
        inputSampleFormat = 0;
2091
        suggestedInputLatencyFrames = 0;
2092
    }
2093

    
2094
    if( outputParameters )
2095
    {
2096
        outputChannelCount = outputParameters->channelCount;
2097
        outputSampleFormat = outputParameters->sampleFormat;
2098
        suggestedOutputLatencyFrames = (unsigned long)((outputParameters->suggestedLatency * sampleRate)+0.5f);
2099

    
2100
        /* unless alternate device specification is supported, reject the use of
2101
            paUseHostApiSpecificDeviceSpecification */
2102
        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
2103
            return paInvalidDevice;
2104

    
2105
        asioDeviceIndex = outputParameters->device;
2106

    
2107
        PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[asioDeviceIndex];
2108

    
2109
        /* validate hostApiSpecificStreamInfo */
2110
        outputStreamInfo = (PaAsioStreamInfo*)outputParameters->hostApiSpecificStreamInfo;
2111
        result = ValidateAsioSpecificStreamInfo( outputParameters, outputStreamInfo,
2112
            asioDeviceInfo->commonDeviceInfo.maxOutputChannels,
2113
            &outputChannelSelectors
2114
        );
2115
        if( result != paNoError ) return result;
2116
    }
2117
    else
2118
    {
2119
        outputChannelCount = 0;
2120
        outputSampleFormat = 0;
2121
        suggestedOutputLatencyFrames = 0;
2122
    }
2123

    
2124
    driverInfo = &asioHostApi->openAsioDriverInfo;
2125

    
2126
    /* NOTE: we load the driver and use its current settings
2127
        rather than the ones in our device info structure which may be stale */
2128

    
2129
    result = LoadAsioDriver( asioHostApi, asioHostApi->inheritedHostApiRep.deviceInfos[ asioDeviceIndex ]->name,
2130
            driverInfo, asioHostApi->systemSpecific );
2131
    if( result == paNoError )
2132
        asioIsInitialized = 1;
2133
    else{
2134
        PA_DEBUG(("OpenStream ERROR1 - LoadAsioDriver returned %d\n", result));
2135
        goto error;
2136
    }
2137

    
2138
    /* check that input device can support inputChannelCount */
2139
    if( inputChannelCount > 0 )
2140
    {
2141
        if( inputChannelCount > driverInfo->inputChannelCount )
2142
        {
2143
            result = paInvalidChannelCount;
2144
            PA_DEBUG(("OpenStream ERROR2\n"));
2145
            goto error;
2146
        }
2147
    }
2148

    
2149
    /* check that output device can support outputChannelCount */
2150
    if( outputChannelCount )
2151
    {
2152
        if( outputChannelCount > driverInfo->outputChannelCount )
2153
        {
2154
            result = paInvalidChannelCount;
2155
            PA_DEBUG(("OpenStream ERROR3\n"));
2156
            goto error;
2157
        }
2158
    }
2159

    
2160
    result = ValidateAndSetSampleRate( sampleRate );
2161
    if( result != paNoError )
2162
        goto error;
2163

    
2164
    /*
2165
        IMPLEMENT ME:
2166
            - if a full duplex stream is requested, check that the combination
2167
                of input and output parameters is supported
2168
    */
2169

    
2170
    /* validate platform specific flags */
2171
    if( (streamFlags & paPlatformSpecificFlags) != 0 ){
2172
        PA_DEBUG(("OpenStream invalid flags!!\n"));
2173
        return paInvalidFlag; /* unexpected platform specific flag */
2174
    }
2175

    
2176

    
2177
    stream = (PaAsioStream*)PaUtil_AllocateMemory( sizeof(PaAsioStream) );
2178
    if( !stream )
2179
    {
2180
        result = paInsufficientMemory;
2181
        PA_DEBUG(("OpenStream ERROR5\n"));
2182
        goto error;
2183
    }
2184
    stream->blockingState = NULL; /* Blocking i/o not initialized, yet. */
2185

    
2186

    
2187
    stream->completedBuffersPlayedEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
2188
    if( stream->completedBuffersPlayedEvent == NULL )
2189
    {
2190
        result = paUnanticipatedHostError;
2191
        PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
2192
        PA_DEBUG(("OpenStream ERROR6\n"));
2193
        goto error;
2194
    }
2195
    completedBuffersPlayedEventInited = 1;
2196

    
2197

    
2198
    stream->asioBufferInfos = 0; /* for deallocation in error */
2199
    stream->asioChannelInfos = 0; /* for deallocation in error */
2200
    stream->bufferPtrs = 0; /* for deallocation in error */
2201

    
2202
    /* Using blocking i/o interface... */
2203
    if( usingBlockingIo )
2204
    {
2205
        /* Blocking i/o is implemented by running callback mode, using a special blocking i/o callback. */
2206
        streamCallback = BlockingIoPaCallback; /* Setup PA to use the ASIO blocking i/o callback. */
2207
        userData       = &theAsioStream;       /* The callback user data will be the PA ASIO stream. */
2208
        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
2209
                                               &asioHostApi->blockingStreamInterface, streamCallback, userData );
2210
    }
2211
    else /* Using callback interface... */
2212
    {
2213
        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
2214
                                               &asioHostApi->callbackStreamInterface, streamCallback, userData );
2215
    }
2216

    
2217

    
2218
    PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
2219

    
2220

    
2221
    stream->asioBufferInfos = (ASIOBufferInfo*)PaUtil_AllocateMemory(
2222
            sizeof(ASIOBufferInfo) * (inputChannelCount + outputChannelCount) );
2223
    if( !stream->asioBufferInfos )
2224
    {
2225
        result = paInsufficientMemory;
2226
        PA_DEBUG(("OpenStream ERROR7\n"));
2227
        goto error;
2228
    }
2229

    
2230

    
2231
    for( i=0; i < inputChannelCount; ++i )
2232
    {
2233
        ASIOBufferInfo *info = &stream->asioBufferInfos[i];
2234

    
2235
        info->isInput = ASIOTrue;
2236

    
2237
        if( inputChannelSelectors ){
2238
            // inputChannelSelectors values have already been validated in
2239
            // ValidateAsioSpecificStreamInfo() above
2240
            info->channelNum = inputChannelSelectors[i];
2241
        }else{
2242
            info->channelNum = i;
2243
        }
2244

    
2245
        info->buffers[0] = info->buffers[1] = 0;
2246
    }
2247

    
2248
    for( i=0; i < outputChannelCount; ++i ){
2249
        ASIOBufferInfo *info = &stream->asioBufferInfos[inputChannelCount+i];
2250

    
2251
        info->isInput = ASIOFalse;
2252

    
2253
        if( outputChannelSelectors ){
2254
            // outputChannelSelectors values have already been validated in
2255
            // ValidateAsioSpecificStreamInfo() above
2256
            info->channelNum = outputChannelSelectors[i];
2257
        }else{
2258
            info->channelNum = i;
2259
        }
2260
        
2261
        info->buffers[0] = info->buffers[1] = 0;
2262
    }
2263

    
2264

    
2265
    /* Using blocking i/o interface... */
2266
    if( usingBlockingIo )
2267
    {
2268
/** @todo REVIEW selection of host buffer size for blocking i/o */
2269

    
2270
        framesPerHostBuffer = SelectHostBufferSize( 0, framesPerBuffer, driverInfo );
2271

    
2272
    }
2273
    else /* Using callback interface... */
2274
    {
2275
        /* Select the host buffer size based on user framesPerBuffer and the
2276
           maximum of suggestedInputLatencyFrames and 
2277
           suggestedOutputLatencyFrames.
2278

2279
           We should subtract any fixed known driver latency from 
2280
           suggestedLatencyFrames before computing the host buffer size.
2281
           However, the ASIO API doesn't provide a method for determining fixed 
2282
           latencies independent of the host buffer size. ASIOGetLatencies()  
2283
           only returns latencies after the buffer size has been configured, so 
2284
           we can't reliably use it to determine fixed latencies here.
2285

2286
           We could set the preferred buffer size and then subtract it from
2287
           the values returned from ASIOGetLatencies, but this would not be 100%
2288
           reliable, so we don't do it.
2289
        */
2290

    
2291
        unsigned long targetBufferingLatencyFrames = 
2292
                (( suggestedInputLatencyFrames > suggestedOutputLatencyFrames )
2293
                ? suggestedInputLatencyFrames 
2294
                : suggestedOutputLatencyFrames);
2295

    
2296
        framesPerHostBuffer = SelectHostBufferSize( targetBufferingLatencyFrames, 
2297
                framesPerBuffer, driverInfo );
2298
    }
2299

    
2300

    
2301
    PA_DEBUG(("PaAsioOpenStream: framesPerHostBuffer :%d\n",  framesPerHostBuffer));
2302

    
2303
    asioError = ASIOCreateBuffers( stream->asioBufferInfos,
2304
            inputChannelCount+outputChannelCount,
2305
            framesPerHostBuffer, &asioCallbacks_ );
2306

    
2307
    if( asioError != ASE_OK
2308
            && framesPerHostBuffer != (unsigned long)driverInfo->bufferPreferredSize )
2309
    {
2310
        PA_DEBUG(("ERROR: ASIOCreateBuffers: %s\n", PaAsio_GetAsioErrorText(asioError) ));
2311
        /*
2312
            Some buggy drivers (like the Hoontech DSP24) give incorrect
2313
            [min, preferred, max] values They should work with the preferred size
2314
            value, thus if Pa_ASIO_CreateBuffers fails with the hostBufferSize
2315
            computed in SelectHostBufferSize, we try again with the preferred size.
2316
        */
2317

    
2318
        framesPerHostBuffer = driverInfo->bufferPreferredSize;
2319

    
2320
        PA_DEBUG(("PaAsioOpenStream: CORRECTED framesPerHostBuffer :%d\n",  framesPerHostBuffer));
2321

    
2322
        ASIOError asioError2 = ASIOCreateBuffers( stream->asioBufferInfos,
2323
                inputChannelCount+outputChannelCount,
2324
                 framesPerHostBuffer, &asioCallbacks_ );
2325
        if( asioError2 == ASE_OK )
2326
            asioError = ASE_OK;
2327
    }
2328

    
2329
    if( asioError != ASE_OK )
2330
    {
2331
        result = paUnanticipatedHostError;
2332
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
2333
        PA_DEBUG(("OpenStream ERROR9\n"));
2334
        goto error;
2335
    }
2336

    
2337
    asioBuffersCreated = 1;
2338

    
2339
    stream->asioChannelInfos = (ASIOChannelInfo*)PaUtil_AllocateMemory(
2340
            sizeof(ASIOChannelInfo) * (inputChannelCount + outputChannelCount) );
2341
    if( !stream->asioChannelInfos )
2342
    {
2343
        result = paInsufficientMemory;
2344
        PA_DEBUG(("OpenStream ERROR10\n"));
2345
        goto error;
2346
    }
2347

    
2348
    for( i=0; i < inputChannelCount + outputChannelCount; ++i )
2349
    {
2350
        stream->asioChannelInfos[i].channel = stream->asioBufferInfos[i].channelNum;
2351
        stream->asioChannelInfos[i].isInput = stream->asioBufferInfos[i].isInput;
2352
        asioError = ASIOGetChannelInfo( &stream->asioChannelInfos[i] );
2353
        if( asioError != ASE_OK )
2354
        {
2355
            result = paUnanticipatedHostError;
2356
            PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
2357
            PA_DEBUG(("OpenStream ERROR11\n"));
2358
            goto error;
2359
        }
2360
    }
2361

    
2362
    stream->bufferPtrs = (void**)PaUtil_AllocateMemory(
2363
            2 * sizeof(void*) * (inputChannelCount + outputChannelCount) );
2364
    if( !stream->bufferPtrs )
2365
    {
2366
        result = paInsufficientMemory;
2367
        PA_DEBUG(("OpenStream ERROR12\n"));
2368
        goto error;
2369
    }
2370

    
2371
    if( inputChannelCount > 0 )
2372
    {
2373
        stream->inputBufferPtrs[0] = stream-> bufferPtrs;
2374
        stream->inputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount];
2375

    
2376
        for( i=0; i<inputChannelCount; ++i )
2377
        {
2378
            stream->inputBufferPtrs[0][i] = stream->asioBufferInfos[i].buffers[0];
2379
            stream->inputBufferPtrs[1][i] = stream->asioBufferInfos[i].buffers[1];
2380
        }
2381
    }
2382
    else
2383
    {
2384
        stream->inputBufferPtrs[0] = 0;
2385
        stream->inputBufferPtrs[1] = 0;
2386
    }
2387

    
2388
    if( outputChannelCount > 0 )
2389
    {
2390
        stream->outputBufferPtrs[0] = &stream->bufferPtrs[inputChannelCount*2];
2391
        stream->outputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount*2 + outputChannelCount];
2392

    
2393
        for( i=0; i<outputChannelCount; ++i )
2394
        {
2395
            stream->outputBufferPtrs[0][i] = stream->asioBufferInfos[inputChannelCount+i].buffers[0];
2396
            stream->outputBufferPtrs[1][i] = stream->asioBufferInfos[inputChannelCount+i].buffers[1];
2397
        }
2398
    }
2399
    else
2400
    {
2401
        stream->outputBufferPtrs[0] = 0;
2402
        stream->outputBufferPtrs[1] = 0;
2403
    }
2404

    
2405
    if( inputChannelCount > 0 )
2406
    {
2407
        /* FIXME: assume all channels use the same type for now 
2408
        
2409
            see: "ASIO devices with multiple sample formats are unsupported"
2410
            http://www.portaudio.com/trac/ticket/106
2411
        */
2412
        ASIOSampleType inputType = stream->asioChannelInfos[0].type;
2413

    
2414
        PA_DEBUG(("ASIO Input  type:%d",inputType));
2415
        AsioSampleTypeLOG(inputType);
2416
        hostInputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( inputType );
2417

    
2418
        SelectAsioToPaConverter( inputType, &stream->inputBufferConverter, &stream->inputShift );
2419
    }
2420
    else
2421
    {
2422
        hostInputSampleFormat = 0;
2423
        stream->inputBufferConverter = 0;
2424
    }
2425

    
2426
    if( outputChannelCount > 0 )
2427
    {
2428
        /* FIXME: assume all channels use the same type for now 
2429
        
2430
            see: "ASIO devices with multiple sample formats are unsupported"
2431
            http://www.portaudio.com/trac/ticket/106
2432
        */
2433
        ASIOSampleType outputType = stream->asioChannelInfos[inputChannelCount].type;
2434

    
2435
        PA_DEBUG(("ASIO Output type:%d",outputType));
2436
        AsioSampleTypeLOG(outputType);
2437
        hostOutputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( outputType );
2438

    
2439
        SelectPaToAsioConverter( outputType, &stream->outputBufferConverter, &stream->outputShift );
2440
    }
2441
    else
2442
    {
2443
        hostOutputSampleFormat = 0;
2444
        stream->outputBufferConverter = 0;
2445
    }
2446

    
2447
    /* Values returned by ASIOGetLatencies() include the latency introduced by 
2448
       the ASIO double buffer. */
2449
    ASIOGetLatencies( &stream->asioInputLatencyFrames, &stream->asioOutputLatencyFrames );
2450

    
2451

    
2452
    /* Using blocking i/o interface... */
2453
    if( usingBlockingIo )
2454
    {
2455
        /* Allocate the blocking i/o input ring buffer memory. */
2456
        stream->blockingState = (PaAsioStreamBlockingState*)PaUtil_AllocateMemory( sizeof(PaAsioStreamBlockingState) );
2457
        if( !stream->blockingState )
2458
        {
2459
            result = paInsufficientMemory;
2460
            PA_DEBUG(("ERROR! Blocking i/o interface struct allocation failed in OpenStream()\n"));
2461
            goto error;
2462
        }
2463

    
2464
        /* Initialize blocking i/o interface struct. */
2465
        stream->blockingState->readFramesReadyEvent   = NULL; /* Uninitialized, yet. */
2466
        stream->blockingState->writeBuffersReadyEvent = NULL; /* Uninitialized, yet. */
2467
        stream->blockingState->readRingBufferData     = NULL; /* Uninitialized, yet. */
2468
        stream->blockingState->writeRingBufferData    = NULL; /* Uninitialized, yet. */
2469
        stream->blockingState->readStreamBuffer       = NULL; /* Uninitialized, yet. */
2470
        stream->blockingState->writeStreamBuffer      = NULL; /* Uninitialized, yet. */
2471
        stream->blockingState->stopFlag               = TRUE; /* Not started, yet. */
2472

    
2473

    
2474
        /* If the user buffer is unspecified */
2475
        if( framesPerBuffer == paFramesPerBufferUnspecified )
2476
        {
2477
            /* Make the user buffer the same size as the host buffer. */
2478
            framesPerBuffer = framesPerHostBuffer;
2479
        }
2480

    
2481

    
2482
        /* Initialize callback buffer processor. */
2483
        result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor               ,
2484
                                                    inputChannelCount                     ,
2485
                                                    inputSampleFormat & ~paNonInterleaved , /* Ring buffer. */
2486
                                                    (hostInputSampleFormat | paNonInterleaved), /* Host format. */
2487
                                                    outputChannelCount                    ,
2488
                                                    outputSampleFormat & ~paNonInterleaved, /* Ring buffer. */
2489
                                                    (hostOutputSampleFormat | paNonInterleaved), /* Host format. */
2490
                                                    sampleRate                            ,
2491
                                                    streamFlags                           ,
2492
                                                    framesPerBuffer                       , /* Frames per ring buffer block. */
2493
                                                    framesPerHostBuffer                   , /* Frames per asio buffer. */
2494
                                                    paUtilFixedHostBufferSize             ,
2495
                                                    streamCallback                        ,
2496
                                                    userData                               );
2497
        if( result != paNoError ){
2498
            PA_DEBUG(("OpenStream ERROR13\n"));
2499
            goto error;
2500
        }
2501
        callbackBufferProcessorInited = TRUE;
2502

    
2503
        /* Initialize the blocking i/o buffer processor. */
2504
        result = PaUtil_InitializeBufferProcessor(&stream->blockingState->bufferProcessor,
2505
                                                   inputChannelCount                     ,
2506
                                                   inputSampleFormat                     , /* User format. */
2507
                                                   inputSampleFormat & ~paNonInterleaved , /* Ring buffer. */
2508
                                                   outputChannelCount                    ,
2509
                                                   outputSampleFormat                    , /* User format. */
2510
                                                   outputSampleFormat & ~paNonInterleaved, /* Ring buffer. */
2511
                                                   sampleRate                            ,
2512
                                                   paClipOff | paDitherOff               , /* Don't use dither nor clipping. */
2513
                                                   framesPerBuffer                       , /* Frames per user buffer. */
2514
                                                   framesPerBuffer                       , /* Frames per ring buffer block. */
2515
                                                   paUtilBoundedHostBufferSize           ,
2516
                                                   NULL, NULL                            );/* No callback! */
2517
        if( result != paNoError ){
2518
            PA_DEBUG(("ERROR! Blocking i/o buffer processor initialization failed in OpenStream()\n"));
2519
            goto error;
2520
        }
2521
        blockingBufferProcessorInited = TRUE;
2522

    
2523
        /* If input is requested. */
2524
        if( inputChannelCount )
2525
        {
2526
            /* Create the callback sync-event. */
2527
            stream->blockingState->readFramesReadyEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
2528
            if( stream->blockingState->readFramesReadyEvent == NULL )
2529
            {
2530
                result = paUnanticipatedHostError;
2531
                PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
2532
                PA_DEBUG(("ERROR! Blocking i/o \"read frames ready\" event creation failed in OpenStream()\n"));
2533
                goto error;
2534
            }
2535
            blockingReadFramesReadyEventInitialized = 1;
2536

    
2537

    
2538
            /* Create pointer buffer to access non-interleaved data in ReadStream() */
2539
            stream->blockingState->readStreamBuffer = (void**)PaUtil_AllocateMemory( sizeof(void*) * inputChannelCount );
2540
            if( !stream->blockingState->readStreamBuffer )
2541
            {
2542
                result = paInsufficientMemory;
2543
                PA_DEBUG(("ERROR! Blocking i/o read stream buffer allocation failed in OpenStream()\n"));
2544
                goto error;
2545
            }
2546

    
2547
            /* The ring buffer should store as many data blocks as needed
2548
               to achieve the requested latency. Whereas it must be large
2549
               enough to store at least two complete data blocks.
2550

2551
               1) Determine the amount of latency to be added to the
2552
                  prefered ASIO latency.
2553
               2) Make sure we have at lest one additional latency frame.
2554
               3) Divide the number of frames by the desired block size to
2555
                  get the number (rounded up to pure integer) of blocks to
2556
                  be stored in the buffer.
2557
               4) Add one additional block for block processing and convert
2558
                  to samples frames.
2559
               5) Get the next larger (or equal) power-of-two buffer size.
2560
             */
2561
            lBlockingBufferSize = suggestedInputLatencyFrames - stream->asioInputLatencyFrames;
2562
            lBlockingBufferSize = (lBlockingBufferSize > 0) ? lBlockingBufferSize : 1;
2563
            lBlockingBufferSize = (lBlockingBufferSize + framesPerBuffer - 1) / framesPerBuffer;
2564
            lBlockingBufferSize = (lBlockingBufferSize + 1) * framesPerBuffer;
2565

    
2566
            /* Get the next larger or equal power-of-two buffersize. */
2567
            lBlockingBufferSizePow2 = 1;
2568
            while( lBlockingBufferSize > (lBlockingBufferSizePow2<<=1) );
2569
            lBlockingBufferSize = lBlockingBufferSizePow2;
2570

    
2571
            /* Compute total intput latency in seconds */
2572
            stream->streamRepresentation.streamInfo.inputLatency =
2573
                (double)( PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor               )
2574
                        + PaUtil_GetBufferProcessorInputLatencyFrames(&stream->blockingState->bufferProcessor)
2575
                        + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer
2576
                        + stream->asioInputLatencyFrames )
2577
                / sampleRate;
2578

    
2579
            /* The code below prints the ASIO latency which doesn't include
2580
               the buffer processor latency nor the blocking i/o latency. It
2581
               reports the added latency separately.
2582
            */
2583
            PA_DEBUG(("PaAsio : ASIO InputLatency = %ld (%ld ms),\n         added buffProc:%ld (%ld ms),\n         added blocking:%ld (%ld ms)\n",
2584
                stream->asioInputLatencyFrames,
2585
                (long)( stream->asioInputLatencyFrames * (1000.0 / sampleRate) ),
2586
                PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor),
2587
                (long)( PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor) * (1000.0 / sampleRate) ),
2588
                PaUtil_GetBufferProcessorInputLatencyFrames(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer,
2589
                (long)( (PaUtil_GetBufferProcessorInputLatencyFrames(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer) * (1000.0 / sampleRate) )
2590
                ));
2591

    
2592
            /* Determine the size of ring buffer in bytes. */
2593
            lBytesPerFrame = inputChannelCount * Pa_GetSampleSize(inputSampleFormat );
2594

    
2595
            /* Allocate the blocking i/o input ring buffer memory. */
2596
            stream->blockingState->readRingBufferData = (void*)PaUtil_AllocateMemory( lBlockingBufferSize * lBytesPerFrame );
2597
            if( !stream->blockingState->readRingBufferData )
2598
            {
2599
                result = paInsufficientMemory;
2600
                PA_DEBUG(("ERROR! Blocking i/o input ring buffer allocation failed in OpenStream()\n"));
2601
                goto error;
2602
            }
2603

    
2604
            /* Initialize the input ring buffer struct. */
2605
            PaUtil_InitializeRingBuffer( &stream->blockingState->readRingBuffer    ,
2606
                                          lBytesPerFrame                           ,
2607
                                          lBlockingBufferSize                      ,
2608
                                          stream->blockingState->readRingBufferData );
2609
        }
2610

    
2611
        /* If output is requested. */
2612
        if( outputChannelCount )
2613
        {
2614
            stream->blockingState->writeBuffersReadyEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
2615
            if( stream->blockingState->writeBuffersReadyEvent == NULL )
2616
            {
2617
                result = paUnanticipatedHostError;
2618
                PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
2619
                PA_DEBUG(("ERROR! Blocking i/o \"write buffers ready\" event creation failed in OpenStream()\n"));
2620
                goto error;
2621
            }
2622
            blockingWriteBuffersReadyEventInitialized = 1;
2623

    
2624
            /* Create pointer buffer to access non-interleaved data in WriteStream() */
2625
            stream->blockingState->writeStreamBuffer = (const void**)PaUtil_AllocateMemory( sizeof(const void*) * outputChannelCount );
2626
            if( !stream->blockingState->writeStreamBuffer )
2627
            {
2628
                result = paInsufficientMemory;
2629
                PA_DEBUG(("ERROR! Blocking i/o write stream buffer allocation failed in OpenStream()\n"));
2630
                goto error;
2631
            }
2632

    
2633
            /* The ring buffer should store as many data blocks as needed
2634
               to achieve the requested latency. Whereas it must be large
2635
               enough to store at least two complete data blocks.
2636

2637
               1) Determine the amount of latency to be added to the
2638
                  prefered ASIO latency.
2639
               2) Make sure we have at lest one additional latency frame.
2640
               3) Divide the number of frames by the desired block size to
2641
                  get the number (rounded up to pure integer) of blocks to
2642
                  be stored in the buffer.
2643
               4) Add one additional block for block processing and convert
2644
                  to samples frames.
2645
               5) Get the next larger (or equal) power-of-two buffer size.
2646
             */
2647
            lBlockingBufferSize = suggestedOutputLatencyFrames - stream->asioOutputLatencyFrames;
2648
            lBlockingBufferSize = (lBlockingBufferSize > 0) ? lBlockingBufferSize : 1;
2649
            lBlockingBufferSize = (lBlockingBufferSize + framesPerBuffer - 1) / framesPerBuffer;
2650
            lBlockingBufferSize = (lBlockingBufferSize + 1) * framesPerBuffer;
2651

    
2652
            /* The buffer size (without the additional block) corresponds
2653
               to the initial number of silent samples in the output ring
2654
               buffer. */
2655
            stream->blockingState->writeRingBufferInitialFrames = lBlockingBufferSize - framesPerBuffer;
2656

    
2657
            /* Get the next larger or equal power-of-two buffersize. */
2658
            lBlockingBufferSizePow2 = 1;
2659
            while( lBlockingBufferSize > (lBlockingBufferSizePow2<<=1) );
2660
            lBlockingBufferSize = lBlockingBufferSizePow2;
2661

    
2662
            /* Compute total output latency in seconds */
2663
            stream->streamRepresentation.streamInfo.outputLatency =
2664
                (double)( PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor)
2665
                        + PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->blockingState->bufferProcessor)
2666
                        + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer
2667
                        + stream->asioOutputLatencyFrames )
2668
                / sampleRate;
2669

    
2670
            /* The code below prints the ASIO latency which doesn't include
2671
               the buffer processor latency nor the blocking i/o latency. It
2672
               reports the added latency separately.
2673
            */
2674
            PA_DEBUG(("PaAsio : ASIO OutputLatency = %ld (%ld ms),\n         added buffProc:%ld (%ld ms),\n         added blocking:%ld (%ld ms)\n",
2675
                stream->asioOutputLatencyFrames,
2676
                (long)( stream->asioOutputLatencyFrames * (1000.0 / sampleRate) ),
2677
                PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor),
2678
                (long)( PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor) * (1000.0 / sampleRate) ),
2679
                PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer,
2680
                (long)( (PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer) * (1000.0 / sampleRate) )
2681
                ));
2682

    
2683
            /* Determine the size of ring buffer in bytes. */
2684
            lBytesPerFrame = outputChannelCount * Pa_GetSampleSize(outputSampleFormat);
2685

    
2686
            /* Allocate the blocking i/o output ring buffer memory. */
2687
            stream->blockingState->writeRingBufferData = (void*)PaUtil_AllocateMemory( lBlockingBufferSize * lBytesPerFrame );
2688
            if( !stream->blockingState->writeRingBufferData )
2689
            {
2690
                result = paInsufficientMemory;
2691
                PA_DEBUG(("ERROR! Blocking i/o output ring buffer allocation failed in OpenStream()\n"));
2692
                goto error;
2693
            }
2694

    
2695
            /* Initialize the output ring buffer struct. */
2696
            PaUtil_InitializeRingBuffer( &stream->blockingState->writeRingBuffer    ,
2697
                                          lBytesPerFrame                            ,
2698
                                          lBlockingBufferSize                       ,
2699
                                          stream->blockingState->writeRingBufferData );
2700
        }
2701

    
2702
        stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
2703

    
2704

    
2705
    }
2706
    else /* Using callback interface... */
2707
    {
2708
        result =  PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
2709
                        inputChannelCount, inputSampleFormat, (hostInputSampleFormat | paNonInterleaved),
2710
                        outputChannelCount, outputSampleFormat, (hostOutputSampleFormat | paNonInterleaved),
2711
                        sampleRate, streamFlags, framesPerBuffer,
2712
                        framesPerHostBuffer, paUtilFixedHostBufferSize,
2713
                        streamCallback, userData );
2714
        if( result != paNoError ){
2715
            PA_DEBUG(("OpenStream ERROR13\n"));
2716
            goto error;
2717
        }
2718
        callbackBufferProcessorInited = TRUE;
2719

    
2720
        stream->streamRepresentation.streamInfo.inputLatency =
2721
                (double)( PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor)
2722
                    + stream->asioInputLatencyFrames) / sampleRate;   // seconds
2723
        stream->streamRepresentation.streamInfo.outputLatency =
2724
                (double)( PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor)
2725
                    + stream->asioOutputLatencyFrames) / sampleRate; // seconds
2726
        stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
2727

    
2728
        // the code below prints the ASIO latency which doesn't include the
2729
        // buffer processor latency. it reports the added latency separately
2730
        PA_DEBUG(("PaAsio : ASIO InputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n",
2731
                stream->asioInputLatencyFrames,
2732
                (long)((stream->asioInputLatencyFrames*1000)/ sampleRate),  
2733
                PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor),
2734
                (long)((PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor)*1000)/ sampleRate)
2735
                ));
2736

    
2737
        PA_DEBUG(("PaAsio : ASIO OuputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n",
2738
                stream->asioOutputLatencyFrames,
2739
                (long)((stream->asioOutputLatencyFrames*1000)/ sampleRate), 
2740
                PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor),
2741
                (long)((PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor)*1000)/ sampleRate)
2742
                ));
2743
    }
2744

    
2745
    stream->asioHostApi = asioHostApi;
2746
    stream->framesPerHostCallback = framesPerHostBuffer;
2747

    
2748
    stream->inputChannelCount = inputChannelCount;
2749
    stream->outputChannelCount = outputChannelCount;
2750
    stream->postOutput = driverInfo->postOutput;
2751
    stream->isStopped = 1;
2752
    stream->isActive = 0;
2753
    
2754
    asioHostApi->openAsioDeviceIndex = asioDeviceIndex;
2755

    
2756
    theAsioStream = stream;
2757
    *s = (PaStream*)stream;
2758

    
2759
    return result;
2760

    
2761
error:
2762
    PA_DEBUG(("goto errored\n"));
2763
    if( stream )
2764
    {
2765
        if( stream->blockingState )
2766
        {
2767
            if( blockingBufferProcessorInited )
2768
                PaUtil_TerminateBufferProcessor( &stream->blockingState->bufferProcessor );
2769

    
2770
            if( stream->blockingState->writeRingBufferData )
2771
                PaUtil_FreeMemory( stream->blockingState->writeRingBufferData );
2772
            if( stream->blockingState->writeStreamBuffer )
2773
                PaUtil_FreeMemory( stream->blockingState->writeStreamBuffer );
2774
            if( blockingWriteBuffersReadyEventInitialized )
2775
                CloseHandle( stream->blockingState->writeBuffersReadyEvent );
2776

    
2777
            if( stream->blockingState->readRingBufferData )
2778
                PaUtil_FreeMemory( stream->blockingState->readRingBufferData );
2779
            if( stream->blockingState->readStreamBuffer )
2780
                PaUtil_FreeMemory( stream->blockingState->readStreamBuffer );
2781
            if( blockingReadFramesReadyEventInitialized )
2782
                CloseHandle( stream->blockingState->readFramesReadyEvent );
2783

    
2784
            PaUtil_FreeMemory( stream->blockingState );
2785
        }
2786

    
2787
        if( callbackBufferProcessorInited )
2788
            PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
2789

    
2790
        if( completedBuffersPlayedEventInited )
2791
            CloseHandle( stream->completedBuffersPlayedEvent );
2792

    
2793
        if( stream->asioBufferInfos )
2794
            PaUtil_FreeMemory( stream->asioBufferInfos );
2795

    
2796
        if( stream->asioChannelInfos )
2797
            PaUtil_FreeMemory( stream->asioChannelInfos );
2798

    
2799
        if( stream->bufferPtrs )
2800
            PaUtil_FreeMemory( stream->bufferPtrs );
2801

    
2802
        PaUtil_FreeMemory( stream );
2803
    }
2804

    
2805
    if( asioBuffersCreated )
2806
        ASIODisposeBuffers();
2807

    
2808
    if( asioIsInitialized )
2809
        {
2810
                UnloadAsioDriver();
2811
        }
2812
    return result;
2813
}
2814

    
2815

    
2816
/*
2817
    When CloseStream() is called, the multi-api layer ensures that
2818
    the stream has already been stopped or aborted.
2819
*/
2820
static PaError CloseStream( PaStream* s )
2821
{
2822
    PaError result = paNoError;
2823
    PaAsioStream *stream = (PaAsioStream*)s;
2824

    
2825
    /*
2826
        IMPLEMENT ME:
2827
            - additional stream closing + cleanup
2828
    */
2829

    
2830
    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
2831
    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
2832

    
2833
    stream->asioHostApi->openAsioDeviceIndex = paNoDevice;
2834

    
2835
    CloseHandle( stream->completedBuffersPlayedEvent );
2836

    
2837
    /* Using blocking i/o interface... */
2838
    if( stream->blockingState )
2839
    {
2840
        PaUtil_TerminateBufferProcessor( &stream->blockingState->bufferProcessor );
2841

    
2842
        if( stream->inputChannelCount ) {
2843
            PaUtil_FreeMemory( stream->blockingState->readRingBufferData );
2844
            PaUtil_FreeMemory( stream->blockingState->readStreamBuffer  );
2845
            CloseHandle( stream->blockingState->readFramesReadyEvent );
2846
        }
2847
        if( stream->outputChannelCount ) {
2848
            PaUtil_FreeMemory( stream->blockingState->writeRingBufferData );
2849
            PaUtil_FreeMemory( stream->blockingState->writeStreamBuffer );
2850
            CloseHandle( stream->blockingState->writeBuffersReadyEvent );
2851
        }
2852

    
2853
        PaUtil_FreeMemory( stream->blockingState );
2854
    }
2855

    
2856
    PaUtil_FreeMemory( stream->asioBufferInfos );
2857
    PaUtil_FreeMemory( stream->asioChannelInfos );
2858
    PaUtil_FreeMemory( stream->bufferPtrs );
2859
    PaUtil_FreeMemory( stream );
2860

    
2861
    ASIODisposeBuffers();
2862
    UnloadAsioDriver();
2863

    
2864
    theAsioStream = 0;
2865

    
2866
    return result;
2867
}
2868

    
2869

    
2870
static void bufferSwitch(long index, ASIOBool directProcess)
2871
{
2872
//TAKEN FROM THE ASIO SDK
2873

    
2874
    // the actual processing callback.
2875
    // Beware that this is normally in a seperate thread, hence be sure that
2876
    // you take care about thread synchronization. This is omitted here for
2877
    // simplicity.
2878

    
2879
    // as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs
2880
    // to be created though it will only set the timeInfo.samplePosition and
2881
    // timeInfo.systemTime fields and the according flags
2882

    
2883
    ASIOTime  timeInfo;
2884
    memset( &timeInfo, 0, sizeof (timeInfo) );
2885

    
2886
    // get the time stamp of the buffer, not necessary if no
2887
    // synchronization to other media is required
2888
    if( ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK)
2889
            timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
2890

    
2891
    // Call the real callback
2892
    bufferSwitchTimeInfo( &timeInfo, index, directProcess );
2893
}
2894

    
2895

    
2896
// conversion from 64 bit ASIOSample/ASIOTimeStamp to double float
2897
#if NATIVE_INT64
2898
    #define ASIO64toDouble(a)  (a)
2899
#else
2900
    const double twoRaisedTo32 = 4294967296.;
2901
    #define ASIO64toDouble(a)  ((a).lo + (a).hi * twoRaisedTo32)
2902
#endif
2903

    
2904
static ASIOTime *bufferSwitchTimeInfo( ASIOTime *timeInfo, long index, ASIOBool directProcess )
2905
{
2906
    // the actual processing callback.
2907
    // Beware that this is normally in a seperate thread, hence be sure that
2908
    // you take care about thread synchronization.
2909

    
2910

    
2911
    /* The SDK says the following about the directProcess flag:
2912
        suggests to the host whether it should immediately start processing
2913
        (directProcess == ASIOTrue), or whether its process should be deferred
2914
        because the call comes from a very low level (for instance, a high level
2915
        priority interrupt), and direct processing would cause timing instabilities for
2916
        the rest of the system. If in doubt, directProcess should be set to ASIOFalse.
2917

2918
        We just ignore directProcess. This could cause incompatibilities with
2919
        drivers which really don't want the audio processing to occur in this
2920
        callback, but none have been identified yet.
2921
    */
2922

    
2923
    (void) directProcess; /* suppress unused parameter warning */
2924

    
2925
#if 0
2926
    // store the timeInfo for later use
2927
    asioDriverInfo.tInfo = *timeInfo;
2928

2929
    // get the time stamp of the buffer, not necessary if no
2930
    // synchronization to other media is required
2931

2932
    if (timeInfo->timeInfo.flags & kSystemTimeValid)
2933
            asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime);
2934
    else
2935
            asioDriverInfo.nanoSeconds = 0;
2936

2937
    if (timeInfo->timeInfo.flags & kSamplePositionValid)
2938
            asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
2939
    else
2940
            asioDriverInfo.samples = 0;
2941

2942
    if (timeInfo->timeCode.flags & kTcValid)
2943
            asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
2944
    else
2945
            asioDriverInfo.tcSamples = 0;
2946

2947
    // get the system reference time
2948
    asioDriverInfo.sysRefTime = get_sys_reference_time();
2949
#endif
2950

    
2951
#if 0
2952
    // a few debug messages for the Windows device driver developer
2953
    // tells you the time when driver got its interrupt and the delay until the app receives
2954
    // the event notification.
2955
    static double last_samples = 0;
2956
    char tmp[128];
2957
    sprintf (tmp, "diff: %d / %d ms / %d ms / %d samples                 \n", asioDriverInfo.sysRefTime - (long)(asioDriverInfo.nanoSeconds / 1000000.0), asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)(asioDriverInfo.samples - last_samples));
2958
    OutputDebugString (tmp);
2959
    last_samples = asioDriverInfo.samples;
2960
#endif
2961

    
2962

    
2963
    if( !theAsioStream )
2964
        return 0L;
2965

    
2966
    // protect against reentrancy
2967
    if( PaAsio_AtomicIncrement(&theAsioStream->reenterCount) )
2968
    {
2969
        theAsioStream->reenterError++;
2970
        //DBUG(("bufferSwitchTimeInfo : reentrancy detection = %d\n", asioDriverInfo.reenterError));
2971
        return 0L;
2972
    }
2973

    
2974
    int buffersDone = 0;
2975
    
2976
    do
2977
    {
2978
        if( buffersDone > 0 )
2979
        {
2980
            // this is a reentered buffer, we missed processing it on time
2981
            // set the input overflow and output underflow flags as appropriate
2982
            
2983
            if( theAsioStream->inputChannelCount > 0 )
2984
                theAsioStream->callbackFlags |= paInputOverflow;
2985
                
2986
            if( theAsioStream->outputChannelCount > 0 )
2987
                theAsioStream->callbackFlags |= paOutputUnderflow;
2988
        }
2989
        else
2990
        {
2991
            if( theAsioStream->zeroOutput )
2992
            {
2993
                ZeroOutputBuffers( theAsioStream, index );
2994

    
2995
                // Finally if the driver supports the ASIOOutputReady() optimization,
2996
                // do it here, all data are in place
2997
                if( theAsioStream->postOutput )
2998
                    ASIOOutputReady();
2999

    
3000
                if( theAsioStream->stopProcessing )
3001
                {
3002
                    if( theAsioStream->stopPlayoutCount < 2 )
3003
                    {
3004
                        ++theAsioStream->stopPlayoutCount;
3005
                        if( theAsioStream->stopPlayoutCount == 2 )
3006
                        {
3007
                            theAsioStream->isActive = 0;
3008
                            if( theAsioStream->streamRepresentation.streamFinishedCallback != 0 )
3009
                                theAsioStream->streamRepresentation.streamFinishedCallback( theAsioStream->streamRepresentation.userData );
3010
                            theAsioStream->streamFinishedCallbackCalled = true;
3011
                            SetEvent( theAsioStream->completedBuffersPlayedEvent );
3012
                        }
3013
                    }
3014
                }
3015
            }
3016
            else
3017
            {
3018

    
3019
#if 0
3020
/*
3021
    see: "ASIO callback underflow/overflow buffer slip detection doesn't work"
3022
    http://www.portaudio.com/trac/ticket/110
3023
*/
3024

3025
// test code to try to detect slip conditions... these may work on some systems
3026
// but neither of them work on the RME Digi96
3027

3028
// check that sample delta matches buffer size (otherwise we must have skipped
3029
// a buffer.
3030
static double last_samples = -512;
3031
double samples;
3032
//if( timeInfo->timeCode.flags & kTcValid )
3033
//    samples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
3034
//else
3035
    samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
3036
int delta = samples - last_samples;
3037
//printf( "%d\n", delta);
3038
last_samples = samples;
3039

3040
if( delta > theAsioStream->framesPerHostCallback )
3041
{
3042
    if( theAsioStream->inputChannelCount > 0 )
3043
        theAsioStream->callbackFlags |= paInputOverflow;
3044

3045
    if( theAsioStream->outputChannelCount > 0 )
3046
        theAsioStream->callbackFlags |= paOutputUnderflow;
3047
}
3048

3049
// check that the buffer index is not the previous index (which would indicate
3050
// that a buffer was skipped.
3051
static int previousIndex = 1;
3052
if( index == previousIndex )
3053
{
3054
    if( theAsioStream->inputChannelCount > 0 )
3055
        theAsioStream->callbackFlags |= paInputOverflow;
3056

3057
    if( theAsioStream->outputChannelCount > 0 )
3058
        theAsioStream->callbackFlags |= paOutputUnderflow;
3059
}
3060
previousIndex = index;
3061
#endif
3062

    
3063
                int i;
3064

    
3065
                PaUtil_BeginCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer );
3066

    
3067
                PaStreamCallbackTimeInfo paTimeInfo;
3068

    
3069
                // asio systemTime is supposed to be measured according to the same
3070
                // clock as timeGetTime
3071
                paTimeInfo.currentTime = (ASIO64toDouble( timeInfo->timeInfo.systemTime ) * .000000001);
3072

    
3073
                /* patch from Paul Boege */
3074
                paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime -
3075
                    ((double)theAsioStream->asioInputLatencyFrames/theAsioStream->streamRepresentation.streamInfo.sampleRate);
3076

    
3077
                paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime +
3078
                    ((double)theAsioStream->asioOutputLatencyFrames/theAsioStream->streamRepresentation.streamInfo.sampleRate);
3079

    
3080
                /* old version is buggy because the buffer processor also adds in its latency to the time parameters
3081
                paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime - theAsioStream->streamRepresentation.streamInfo.inputLatency;
3082
                paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime + theAsioStream->streamRepresentation.streamInfo.outputLatency;
3083
                */
3084

    
3085
/* Disabled! Stopping and re-starting the stream causes an input overflow / output underflow. S.Fischer */
3086
#if 0
3087
// detect underflows by checking inter-callback time > 2 buffer period
3088
static double previousTime = -1;
3089
if( previousTime > 0 ){
3090

3091
    double delta = paTimeInfo.currentTime - previousTime;
3092

3093
    if( delta >= 2. * (theAsioStream->framesPerHostCallback / theAsioStream->streamRepresentation.streamInfo.sampleRate) ){
3094
        if( theAsioStream->inputChannelCount > 0 )
3095
            theAsioStream->callbackFlags |= paInputOverflow;
3096

3097
        if( theAsioStream->outputChannelCount > 0 )
3098
            theAsioStream->callbackFlags |= paOutputUnderflow;
3099
    }
3100
}
3101
previousTime = paTimeInfo.currentTime;
3102
#endif
3103

    
3104
                // note that the above input and output times do not need to be
3105
                // adjusted for the latency of the buffer processor -- the buffer
3106
                // processor handles that.
3107

    
3108
                if( theAsioStream->inputBufferConverter )
3109
                {
3110
                    for( i=0; i<theAsioStream->inputChannelCount; i++ )
3111
                    {
3112
                        theAsioStream->inputBufferConverter( theAsioStream->inputBufferPtrs[index][i],
3113
                                theAsioStream->inputShift, theAsioStream->framesPerHostCallback );
3114
                    }
3115
                }
3116

    
3117
                PaUtil_BeginBufferProcessing( &theAsioStream->bufferProcessor, &paTimeInfo, theAsioStream->callbackFlags );
3118

    
3119
                /* reset status flags once they've been passed to the callback */
3120
                theAsioStream->callbackFlags = 0;
3121

    
3122
                PaUtil_SetInputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ );
3123
                for( i=0; i<theAsioStream->inputChannelCount; ++i )
3124
                    PaUtil_SetNonInterleavedInputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->inputBufferPtrs[index][i] );
3125

    
3126
                PaUtil_SetOutputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ );
3127
                for( i=0; i<theAsioStream->outputChannelCount; ++i )
3128
                    PaUtil_SetNonInterleavedOutputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->outputBufferPtrs[index][i] );
3129

    
3130
                int callbackResult;
3131
                if( theAsioStream->stopProcessing )
3132
                    callbackResult = paComplete;
3133
                else
3134
                    callbackResult = paContinue;
3135
                unsigned long framesProcessed = PaUtil_EndBufferProcessing( &theAsioStream->bufferProcessor, &callbackResult );
3136

    
3137
                if( theAsioStream->outputBufferConverter )
3138
                {
3139
                    for( i=0; i<theAsioStream->outputChannelCount; i++ )
3140
                    {
3141
                        theAsioStream->outputBufferConverter( theAsioStream->outputBufferPtrs[index][i],
3142
                                theAsioStream->outputShift, theAsioStream->framesPerHostCallback );
3143
                    }
3144
                }
3145

    
3146
                PaUtil_EndCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer, framesProcessed );
3147

    
3148
                // Finally if the driver supports the ASIOOutputReady() optimization,
3149
                // do it here, all data are in place
3150
                if( theAsioStream->postOutput )
3151
                    ASIOOutputReady();
3152

    
3153
                if( callbackResult == paContinue )
3154
                {
3155
                    /* nothing special to do */
3156
                }
3157
                else if( callbackResult == paAbort )
3158
                {
3159
                    /* finish playback immediately  */
3160
                    theAsioStream->isActive = 0;
3161
                    if( theAsioStream->streamRepresentation.streamFinishedCallback != 0 )
3162
                        theAsioStream->streamRepresentation.streamFinishedCallback( theAsioStream->streamRepresentation.userData );
3163
                    theAsioStream->streamFinishedCallbackCalled = true;
3164
                    SetEvent( theAsioStream->completedBuffersPlayedEvent );
3165
                    theAsioStream->zeroOutput = true;
3166
                }
3167
                else /* paComplete or other non-zero value indicating complete */
3168
                {
3169
                    /* Finish playback once currently queued audio has completed. */
3170
                    theAsioStream->stopProcessing = true;
3171

    
3172
                    if( PaUtil_IsBufferProcessorOutputEmpty( &theAsioStream->bufferProcessor ) )
3173
                    {
3174
                        theAsioStream->zeroOutput = true;
3175
                        theAsioStream->stopPlayoutCount = 0;
3176
                    }
3177
                }
3178
            }
3179
        }
3180
        
3181
        ++buffersDone;
3182
    }while( PaAsio_AtomicDecrement(&theAsioStream->reenterCount) >= 0 );
3183

    
3184
    return 0L;
3185
}
3186

    
3187

    
3188
static void sampleRateChanged(ASIOSampleRate sRate)
3189
{
3190
    // TAKEN FROM THE ASIO SDK
3191
    // do whatever you need to do if the sample rate changed
3192
    // usually this only happens during external sync.
3193
    // Audio processing is not stopped by the driver, actual sample rate
3194
    // might not have even changed, maybe only the sample rate status of an
3195
    // AES/EBU or S/PDIF digital input at the audio device.
3196
    // You might have to update time/sample related conversion routines, etc.
3197

    
3198
    (void) sRate; /* unused parameter */
3199
    PA_DEBUG( ("sampleRateChanged : %d \n", sRate));
3200
}
3201

    
3202
static long asioMessages(long selector, long value, void* message, double* opt)
3203
{
3204
// TAKEN FROM THE ASIO SDK
3205
    // currently the parameters "value", "message" and "opt" are not used.
3206
    long ret = 0;
3207

    
3208
    (void) message; /* unused parameters */
3209
    (void) opt;
3210

    
3211
    PA_DEBUG( ("asioMessages : %d , %d \n", selector, value));
3212

    
3213
    switch(selector)
3214
    {
3215
        case kAsioSelectorSupported:
3216
            if(value == kAsioResetRequest
3217
            || value == kAsioEngineVersion
3218
            || value == kAsioResyncRequest
3219
            || value == kAsioLatenciesChanged
3220
            // the following three were added for ASIO 2.0, you don't necessarily have to support them
3221
            || value == kAsioSupportsTimeInfo
3222
            || value == kAsioSupportsTimeCode
3223
            || value == kAsioSupportsInputMonitor)
3224
                    ret = 1L;
3225
            break;
3226

    
3227
        case kAsioBufferSizeChange:
3228
            //printf("kAsioBufferSizeChange \n");
3229
            break;
3230

    
3231
        case kAsioResetRequest:
3232
            // defer the task and perform the reset of the driver during the next "safe" situation
3233
            // You cannot reset the driver right now, as this code is called from the driver.
3234
            // Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction
3235
            // Afterwards you initialize the driver again.
3236

    
3237
            /*FIXME: commented the next line out
3238

3239
                see: "PA/ASIO ignores some driver notifications it probably shouldn't"
3240
                http://www.portaudio.com/trac/ticket/108
3241
            */
3242
            //asioDriverInfo.stopped;  // In this sample the processing will just stop
3243
            ret = 1L;
3244
            break;
3245

    
3246
        case kAsioResyncRequest:
3247
            // This informs the application, that the driver encountered some non fatal data loss.
3248
            // It is used for synchronization purposes of different media.
3249
            // Added mainly to work around the Win16Mutex problems in Windows 95/98 with the
3250
            // Windows Multimedia system, which could loose data because the Mutex was hold too long
3251
            // by another thread.
3252
            // However a driver can issue it in other situations, too.
3253
            ret = 1L;
3254
            break;
3255

    
3256
        case kAsioLatenciesChanged:
3257
            // This will inform the host application that the drivers were latencies changed.
3258
            // Beware, it this does not mean that the buffer sizes have changed!
3259
            // You might need to update internal delay data.
3260
            ret = 1L;
3261
            //printf("kAsioLatenciesChanged \n");
3262
            break;
3263

    
3264
        case kAsioEngineVersion:
3265
            // return the supported ASIO version of the host application
3266
            // If a host applications does not implement this selector, ASIO 1.0 is assumed
3267
            // by the driver
3268
            ret = 2L;
3269
            break;
3270

    
3271
        case kAsioSupportsTimeInfo:
3272
            // informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback
3273
            // is supported.
3274
            // For compatibility with ASIO 1.0 drivers the host application should always support
3275
            // the "old" bufferSwitch method, too.
3276
            ret = 1;
3277
            break;
3278

    
3279
        case kAsioSupportsTimeCode:
3280
            // informs the driver wether application is interested in time code info.
3281
            // If an application does not need to know about time code, the driver has less work
3282
            // to do.
3283
            ret = 0;
3284
            break;
3285
    }
3286
    return ret;
3287
}
3288

    
3289

    
3290
static PaError StartStream( PaStream *s )
3291
{
3292
    PaError result = paNoError;
3293
    PaAsioStream *stream = (PaAsioStream*)s;
3294
    PaAsioStreamBlockingState *blockingState = stream->blockingState;
3295
    ASIOError asioError;
3296

    
3297
    if( stream->outputChannelCount > 0 )
3298
    {
3299
        ZeroOutputBuffers( stream, 0 );
3300
        ZeroOutputBuffers( stream, 1 );
3301
    }
3302

    
3303
    PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
3304
    stream->stopProcessing = false;
3305
    stream->zeroOutput = false;
3306

    
3307
    /* Reentrancy counter initialisation */
3308
    stream->reenterCount = -1;
3309
    stream->reenterError = 0;
3310

    
3311
    stream->callbackFlags = 0;
3312

    
3313
    if( ResetEvent( stream->completedBuffersPlayedEvent ) == 0 )
3314
    {
3315
        result = paUnanticipatedHostError;
3316
        PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
3317
    }
3318

    
3319

    
3320
    /* Using blocking i/o interface... */
3321
    if( blockingState )
3322
    {
3323
        /* Reset blocking i/o buffer processor. */
3324
        PaUtil_ResetBufferProcessor( &blockingState->bufferProcessor );
3325

    
3326
        /* If we're about to process some input data. */
3327
        if( stream->inputChannelCount )
3328
        {
3329
            /* Reset callback-ReadStream sync event. */
3330
            if( ResetEvent( blockingState->readFramesReadyEvent ) == 0 )
3331
            {
3332
                result = paUnanticipatedHostError;
3333
                PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
3334
            }
3335

    
3336
            /* Flush blocking i/o ring buffer. */
3337
            PaUtil_FlushRingBuffer( &blockingState->readRingBuffer );
3338
            (*blockingState->bufferProcessor.inputZeroer)( blockingState->readRingBuffer.buffer, 1, blockingState->bufferProcessor.inputChannelCount * blockingState->readRingBuffer.bufferSize );
3339
        }
3340

    
3341
        /* If we're about to process some output data. */
3342
        if( stream->outputChannelCount )
3343
        {
3344
            /* Reset callback-WriteStream sync event. */
3345
            if( ResetEvent( blockingState->writeBuffersReadyEvent ) == 0 )
3346
            {
3347
                result = paUnanticipatedHostError;
3348
                PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
3349
            }
3350

    
3351
            /* Flush blocking i/o ring buffer. */
3352
            PaUtil_FlushRingBuffer( &blockingState->writeRingBuffer );
3353
            (*blockingState->bufferProcessor.outputZeroer)( blockingState->writeRingBuffer.buffer, 1, blockingState->bufferProcessor.outputChannelCount * blockingState->writeRingBuffer.bufferSize );
3354

    
3355
            /* Initialize the output ring buffer to "silence". */
3356
            PaUtil_AdvanceRingBufferWriteIndex( &blockingState->writeRingBuffer, blockingState->writeRingBufferInitialFrames );
3357
        }
3358

    
3359
        /* Clear requested frames / buffers count. */
3360
        blockingState->writeBuffersRequested     = 0;
3361
        blockingState->readFramesRequested       = 0;
3362
        blockingState->writeBuffersRequestedFlag = FALSE;
3363
        blockingState->readFramesRequestedFlag   = FALSE;
3364
        blockingState->outputUnderflowFlag       = FALSE;
3365
        blockingState->inputOverflowFlag         = FALSE;
3366
        blockingState->stopFlag                  = FALSE;
3367
    }
3368

    
3369

    
3370
    if( result == paNoError )
3371
    {
3372
        assert( theAsioStream == stream ); /* theAsioStream should be set correctly in OpenStream */
3373

    
3374
        /* initialize these variables before the callback has a chance to be invoked */
3375
        stream->isStopped = 0;
3376
        stream->isActive = 1;
3377
        stream->streamFinishedCallbackCalled = false;
3378

    
3379
        asioError = ASIOStart();
3380
        if( asioError != ASE_OK )
3381
        {
3382
            stream->isStopped = 1;
3383
            stream->isActive = 0;
3384

    
3385
            result = paUnanticipatedHostError;
3386
            PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
3387
        }
3388
    }
3389

    
3390
    return result;
3391
}
3392

    
3393
static void EnsureCallbackHasCompleted( PaAsioStream *stream )
3394
{
3395
    // make sure that the callback is not still in-flight after ASIOStop()
3396
    // returns. This has been observed to happen on the Hoontech DSP24 for
3397
    // example.
3398
    int count = 2000;  // only wait for 2 seconds, rather than hanging.
3399
    while( stream->reenterCount != -1 && count > 0 )
3400
    {
3401
        Sleep(1);
3402
        --count;
3403
    }
3404
}
3405

    
3406
static PaError StopStream( PaStream *s )
3407
{
3408
    PaError result = paNoError;
3409
    PaAsioStream *stream = (PaAsioStream*)s;
3410
    PaAsioStreamBlockingState *blockingState = stream->blockingState;
3411
    ASIOError asioError;
3412

    
3413
    if( stream->isActive )
3414
    {
3415
        /* If blocking i/o output is in use */
3416
        if( blockingState && stream->outputChannelCount )
3417
        {
3418
            /* Request the whole output buffer to be available. */
3419
            blockingState->writeBuffersRequested = blockingState->writeRingBuffer.bufferSize;
3420
            /* Signalize that additional buffers are need. */
3421
            blockingState->writeBuffersRequestedFlag = TRUE;
3422
            /* Set flag to indicate the playback is to be stopped. */
3423
            blockingState->stopFlag = TRUE;
3424

    
3425
            /* Wait until requested number of buffers has been freed. Time
3426
               out after twice the blocking i/o ouput buffer could have
3427
               been consumed. */
3428
            DWORD timeout = (DWORD)( 2 * blockingState->writeRingBuffer.bufferSize * 1000
3429
                                       / stream->streamRepresentation.streamInfo.sampleRate );
3430
            DWORD waitResult = WaitForSingleObject( blockingState->writeBuffersReadyEvent, timeout );
3431

    
3432
            /* If something seriously went wrong... */
3433
            if( waitResult == WAIT_FAILED )
3434
            {
3435
                PA_DEBUG(("WaitForSingleObject() failed in StopStream()\n"));
3436
                result = paUnanticipatedHostError;
3437
                PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
3438
            }
3439
            else if( waitResult == WAIT_TIMEOUT )
3440
            {
3441
                PA_DEBUG(("WaitForSingleObject() timed out in StopStream()\n"));
3442
                result = paTimedOut;
3443
            }
3444
        }
3445

    
3446
        stream->stopProcessing = true;
3447

    
3448
        /* wait for the stream to finish playing out enqueued buffers.
3449
            timeout after four times the stream latency.
3450

3451
            @todo should use a better time out value - if the user buffer
3452
            length is longer than the asio buffer size then that should
3453
            be taken into account.
3454
        */
3455
        if( WaitForSingleObject( stream->completedBuffersPlayedEvent,
3456
                (DWORD)(stream->streamRepresentation.streamInfo.outputLatency * 1000. * 4.) )
3457
                    == WAIT_TIMEOUT )
3458
        {
3459
            PA_DEBUG(("WaitForSingleObject() timed out in StopStream()\n" ));
3460
        }
3461
    }
3462

    
3463
    asioError = ASIOStop();
3464
    if( asioError == ASE_OK )
3465
    {
3466
        EnsureCallbackHasCompleted( stream );
3467
    }
3468
    else
3469
    {
3470
        result = paUnanticipatedHostError;
3471
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
3472
    }
3473

    
3474
    stream->isStopped = 1;
3475
    stream->isActive = 0;
3476

    
3477
    if( !stream->streamFinishedCallbackCalled )
3478
    {
3479
        if( stream->streamRepresentation.streamFinishedCallback != 0 )
3480
            stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
3481
    }
3482

    
3483
    return result;
3484
}
3485

    
3486
static PaError AbortStream( PaStream *s )
3487
{
3488
    PaError result = paNoError;
3489
    PaAsioStream *stream = (PaAsioStream*)s;
3490
    ASIOError asioError;
3491

    
3492
    stream->zeroOutput = true;
3493

    
3494
    asioError = ASIOStop();
3495
    if( asioError == ASE_OK )
3496
    {
3497
        EnsureCallbackHasCompleted( stream );
3498
    }
3499
    else
3500
    {
3501
        result = paUnanticipatedHostError;
3502
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
3503
    }
3504

    
3505
    stream->isStopped = 1;
3506
    stream->isActive = 0;
3507

    
3508
    if( !stream->streamFinishedCallbackCalled )
3509
    {
3510
        if( stream->streamRepresentation.streamFinishedCallback != 0 )
3511
            stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
3512
    }
3513

    
3514
    return result;
3515
}
3516

    
3517

    
3518
static PaError IsStreamStopped( PaStream *s )
3519
{
3520
    PaAsioStream *stream = (PaAsioStream*)s;
3521
    
3522
    return stream->isStopped;
3523
}
3524

    
3525

    
3526
static PaError IsStreamActive( PaStream *s )
3527
{
3528
    PaAsioStream *stream = (PaAsioStream*)s;
3529

    
3530
    return stream->isActive;
3531
}
3532

    
3533

    
3534
static PaTime GetStreamTime( PaStream *s )
3535
{
3536
    (void) s; /* unused parameter */
3537

    
3538
    return (double)timeGetTime() * .001;
3539
}
3540

    
3541

    
3542
static double GetStreamCpuLoad( PaStream* s )
3543
{
3544
    PaAsioStream *stream = (PaAsioStream*)s;
3545

    
3546
    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
3547
}
3548

    
3549

    
3550
/*
3551
    As separate stream interfaces are used for blocking and callback
3552
    streams, the following functions can be guaranteed to only be called
3553
    for blocking streams.
3554
*/
3555

    
3556
static PaError ReadStream( PaStream      *s     ,
3557
                           void          *buffer,
3558
                           unsigned long  frames )
3559
{
3560
    PaError result = paNoError; /* Initial return value. */
3561
    PaAsioStream *stream = (PaAsioStream*)s; /* The PA ASIO stream. */
3562

    
3563
    /* Pointer to the blocking i/o data struct. */
3564
    PaAsioStreamBlockingState *blockingState = stream->blockingState;
3565

    
3566
    /* Get blocking i/o buffer processor and ring buffer pointers. */
3567
    PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor;
3568
    PaUtilRingBuffer      *pRb = &blockingState->readRingBuffer;
3569

    
3570
    /* Ring buffer segment(s) used for writing. */
3571
    void *pRingBufferData1st = NULL; /* First segment. (Mandatory) */
3572
    void *pRingBufferData2nd = NULL; /* Second segment. (Optional) */
3573

    
3574
    /* Number of frames per ring buffer segment. */
3575
    long lRingBufferSize1st = 0; /* First segment. (Mandatory) */
3576
    long lRingBufferSize2nd = 0; /* Second segment. (Optional) */
3577

    
3578
    /* Get number of frames to be processed per data block. */
3579
    unsigned long lFramesPerBlock = stream->bufferProcessor.framesPerUserBuffer;
3580
    /* Actual number of frames that has been copied into the ring buffer. */
3581
    unsigned long lFramesCopied = 0;
3582
    /* The number of remaining unprocessed dtat frames. */
3583
    unsigned long lFramesRemaining = frames;
3584

    
3585
    /* Copy the input argument to avoid pointer increment! */
3586
    const void *userBuffer;
3587
    unsigned int i; /* Just a counter. */
3588

    
3589
    /* About the time, needed to process 8 data blocks. */
3590
    DWORD timeout = (DWORD)( 8 * lFramesPerBlock * 1000 / stream->streamRepresentation.streamInfo.sampleRate );
3591
    DWORD waitResult = 0;
3592

    
3593

    
3594
    /* Check if the stream is still available ready to gather new data. */
3595
    if( blockingState->stopFlag || !stream->isActive )
3596
    {
3597
        PA_DEBUG(("Warning! Stream no longer available for reading in ReadStream()\n"));
3598
        result = paStreamIsStopped;
3599
        return result;
3600
    }
3601

    
3602
    /* If the stream is a input stream. */
3603
    if( stream->inputChannelCount )
3604
    {
3605
        /* Prepare buffer access. */
3606
        if( !pBp->userOutputIsInterleaved )
3607
        {
3608
            userBuffer = blockingState->readStreamBuffer;
3609
            for( i = 0; i<pBp->inputChannelCount; ++i )
3610
            {
3611
                ((void**)userBuffer)[i] = ((void**)buffer)[i];
3612
            }
3613
        } /* Use the unchanged buffer. */
3614
        else { userBuffer = buffer; }
3615

    
3616
        do /* Internal block processing for too large user data buffers. */
3617
        {
3618
            /* Get the size of the current data block to be processed. */
3619
            lFramesPerBlock =(lFramesPerBlock < lFramesRemaining)
3620
                            ? lFramesPerBlock : lFramesRemaining;
3621
            /* Use predefined block size for as long there are enough
3622
               buffers available, thereafter reduce the processing block
3623
               size to match the number of remaining buffers. So the final
3624
               data block is processed although it may be incomplete. */
3625

    
3626
            /* If the available amount of data frames is insufficient. */
3627
            if( PaUtil_GetRingBufferReadAvailable(pRb) < (long) lFramesPerBlock )
3628
            {
3629
                /* Make sure, the event isn't already set! */
3630
                /* ResetEvent( blockingState->readFramesReadyEvent ); */
3631

    
3632
                /* Set the number of requested buffers. */
3633
                blockingState->readFramesRequested = lFramesPerBlock;
3634

    
3635
                /* Signalize that additional buffers are need. */
3636
                blockingState->readFramesRequestedFlag = TRUE;
3637

    
3638
                /* Wait until requested number of buffers has been freed. */
3639
                waitResult = WaitForSingleObject( blockingState->readFramesReadyEvent, timeout );
3640

    
3641
                /* If something seriously went wrong... */
3642
                if( waitResult == WAIT_FAILED )
3643
                {
3644
                    PA_DEBUG(("WaitForSingleObject() failed in ReadStream()\n"));
3645
                    result = paUnanticipatedHostError;
3646
                    PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
3647
                    return result;
3648
                }
3649
                else if( waitResult == WAIT_TIMEOUT )
3650
                {
3651
                    PA_DEBUG(("WaitForSingleObject() timed out in ReadStream()\n"));
3652

    
3653
                    /* If block processing has stopped, abort! */
3654
                    if( blockingState->stopFlag ) { return result = paStreamIsStopped; }
3655

    
3656
                    /* If a timeout is encountered, give up eventually. */
3657
                    return result = paTimedOut;
3658
                }
3659
            }
3660
            /* Now, the ring buffer contains the required amount of data
3661
               frames.
3662
               (Therefor we don't need to check the return argument of
3663
               PaUtil_GetRingBufferReadRegions(). ;-) )
3664
            */
3665

    
3666
            /* Retrieve pointer(s) to the ring buffer's current write
3667
               position(s). If the first buffer segment is too small to
3668
               store the requested number of bytes, an additional second
3669
               segment is returned. Otherwise, i.e. if the first segment
3670
               is large enough, the second segment's pointer will be NULL.
3671
            */
3672
            PaUtil_GetRingBufferReadRegions(pRb                ,
3673
                                            lFramesPerBlock    ,
3674
                                            &pRingBufferData1st,
3675
                                            &lRingBufferSize1st,
3676
                                            &pRingBufferData2nd,
3677
                                            &lRingBufferSize2nd);
3678

    
3679
            /* Set number of frames to be copied from the ring buffer. */
3680
            PaUtil_SetInputFrameCount( pBp, lRingBufferSize1st ); 
3681
            /* Setup ring buffer access. */
3682
            PaUtil_SetInterleavedInputChannels(pBp               ,  /* Buffer processor. */
3683
                                               0                 ,  /* The first channel's index. */
3684
                                               pRingBufferData1st,  /* First ring buffer segment. */
3685
                                               0                 ); /* Use all available channels. */
3686

    
3687
            /* If a second ring buffer segment is required. */
3688
            if( lRingBufferSize2nd ) {
3689
                /* Set number of frames to be copied from the ring buffer. */
3690
                PaUtil_Set2ndInputFrameCount( pBp, lRingBufferSize2nd );
3691
                /* Setup ring buffer access. */
3692
                PaUtil_Set2ndInterleavedInputChannels(pBp               ,  /* Buffer processor. */
3693
                                                      0                 ,  /* The first channel's index. */
3694
                                                      pRingBufferData2nd,  /* Second ring buffer segment. */
3695
                                                      0                 ); /* Use all available channels. */
3696
            }
3697

    
3698
            /* Let the buffer processor handle "copy and conversion" and
3699
               update the ring buffer indices manually. */
3700
            lFramesCopied = PaUtil_CopyInput( pBp, &buffer, lFramesPerBlock );
3701
            PaUtil_AdvanceRingBufferReadIndex( pRb, lFramesCopied );
3702

    
3703
            /* Decrease number of unprocessed frames. */
3704
            lFramesRemaining -= lFramesCopied;
3705

    
3706
        } /* Continue with the next data chunk. */
3707
        while( lFramesRemaining );
3708

    
3709

    
3710
        /* If there has been an input overflow within the callback */
3711
        if( blockingState->inputOverflowFlag )
3712
        {
3713
            blockingState->inputOverflowFlag = FALSE;
3714

    
3715
            /* Return the corresponding error code. */
3716
            result = paInputOverflowed;
3717
        }
3718

    
3719
    } /* If this is not an input stream. */
3720
    else {
3721
        result = paCanNotReadFromAnOutputOnlyStream;
3722
    }
3723

    
3724
    return result;
3725
}
3726

    
3727
static PaError WriteStream( PaStream      *s     ,
3728
                            const void    *buffer,
3729
                            unsigned long  frames )
3730
{
3731
    PaError result = paNoError; /* Initial return value. */
3732
    PaAsioStream *stream = (PaAsioStream*)s; /* The PA ASIO stream. */
3733

    
3734
    /* Pointer to the blocking i/o data struct. */
3735
    PaAsioStreamBlockingState *blockingState = stream->blockingState;
3736

    
3737
    /* Get blocking i/o buffer processor and ring buffer pointers. */
3738
    PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor;
3739
    PaUtilRingBuffer      *pRb = &blockingState->writeRingBuffer;
3740

    
3741
    /* Ring buffer segment(s) used for writing. */
3742
    void *pRingBufferData1st = NULL; /* First segment. (Mandatory) */
3743
    void *pRingBufferData2nd = NULL; /* Second segment. (Optional) */
3744

    
3745
    /* Number of frames per ring buffer segment. */
3746
    long lRingBufferSize1st = 0; /* First segment. (Mandatory) */
3747
    long lRingBufferSize2nd = 0; /* Second segment. (Optional) */
3748

    
3749
    /* Get number of frames to be processed per data block. */
3750
    unsigned long lFramesPerBlock = stream->bufferProcessor.framesPerUserBuffer;
3751
    /* Actual number of frames that has been copied into the ring buffer. */
3752
    unsigned long lFramesCopied = 0;
3753
    /* The number of remaining unprocessed dtat frames. */
3754
    unsigned long lFramesRemaining = frames;
3755

    
3756
    /* About the time, needed to process 8 data blocks. */
3757
    DWORD timeout = (DWORD)( 8 * lFramesPerBlock * 1000 / stream->streamRepresentation.streamInfo.sampleRate );
3758
    DWORD waitResult = 0;
3759

    
3760
    /* Copy the input argument to avoid pointer increment! */
3761
    const void *userBuffer;
3762
    unsigned int i; /* Just a counter. */
3763

    
3764

    
3765
    /* Check if the stream ist still available ready to recieve new data. */
3766
    if( blockingState->stopFlag || !stream->isActive )
3767
    {
3768
        PA_DEBUG(("Warning! Stream no longer available for writing in WriteStream()\n"));
3769
        result = paStreamIsStopped;
3770
        return result;
3771
    }
3772

    
3773
    /* If the stream is a output stream. */
3774
    if( stream->outputChannelCount )
3775
    {
3776
        /* Prepare buffer access. */
3777
        if( !pBp->userOutputIsInterleaved )
3778
        {
3779
            userBuffer = blockingState->writeStreamBuffer;
3780
            for( i = 0; i<pBp->outputChannelCount; ++i )
3781
            {
3782
                ((const void**)userBuffer)[i] = ((const void**)buffer)[i];
3783
            }
3784
        } /* Use the unchanged buffer. */
3785
        else { userBuffer = buffer; }
3786

    
3787

    
3788
        do /* Internal block processing for too large user data buffers. */
3789
        {
3790
            /* Get the size of the current data block to be processed. */
3791
            lFramesPerBlock =(lFramesPerBlock < lFramesRemaining)
3792
                            ? lFramesPerBlock : lFramesRemaining;
3793
            /* Use predefined block size for as long there are enough
3794
               frames available, thereafter reduce the processing block
3795
               size to match the number of remaining frames. So the final
3796
               data block is processed although it may be incomplete. */
3797

    
3798
            /* If the available amount of buffers is insufficient. */
3799
            if( PaUtil_GetRingBufferWriteAvailable(pRb) < (long) lFramesPerBlock )
3800
            {
3801
                /* Make sure, the event isn't already set! */
3802
                /* ResetEvent( blockingState->writeBuffersReadyEvent ); */
3803

    
3804
                /* Set the number of requested buffers. */
3805
                blockingState->writeBuffersRequested = lFramesPerBlock;
3806

    
3807
                /* Signalize that additional buffers are need. */
3808
                blockingState->writeBuffersRequestedFlag = TRUE;
3809

    
3810
                /* Wait until requested number of buffers has been freed. */
3811
                waitResult = WaitForSingleObject( blockingState->writeBuffersReadyEvent, timeout );
3812

    
3813
                /* If something seriously went wrong... */
3814
                if( waitResult == WAIT_FAILED )
3815
                {
3816
                    PA_DEBUG(("WaitForSingleObject() failed in WriteStream()\n"));
3817
                    result = paUnanticipatedHostError;
3818
                    PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
3819
                    return result;
3820
                }
3821
                else if( waitResult == WAIT_TIMEOUT )
3822
                {
3823
                    PA_DEBUG(("WaitForSingleObject() timed out in WriteStream()\n"));
3824

    
3825
                    /* If block processing has stopped, abort! */
3826
                    if( blockingState->stopFlag ) { return result = paStreamIsStopped; }
3827
                    
3828
                    /* If a timeout is encountered, give up eventually. */
3829
                    return result = paTimedOut;
3830
                }
3831
            }
3832
            /* Now, the ring buffer contains the required amount of free
3833
               space to store the provided number of data frames.
3834
               (Therefor we don't need to check the return argument of
3835
               PaUtil_GetRingBufferWriteRegions(). ;-) )
3836
            */
3837

    
3838
            /* Retrieve pointer(s) to the ring buffer's current write
3839
               position(s). If the first buffer segment is too small to
3840
               store the requested number of bytes, an additional second
3841
               segment is returned. Otherwise, i.e. if the first segment
3842
               is large enough, the second segment's pointer will be NULL.
3843
            */
3844
            PaUtil_GetRingBufferWriteRegions(pRb                ,
3845
                                             lFramesPerBlock    ,
3846
                                             &pRingBufferData1st,
3847
                                             &lRingBufferSize1st,
3848
                                             &pRingBufferData2nd,
3849
                                             &lRingBufferSize2nd);
3850

    
3851
            /* Set number of frames to be copied to the ring buffer. */
3852
            PaUtil_SetOutputFrameCount( pBp, lRingBufferSize1st ); 
3853
            /* Setup ring buffer access. */
3854
            PaUtil_SetInterleavedOutputChannels(pBp               ,  /* Buffer processor. */
3855
                                                0                 ,  /* The first channel's index. */
3856
                                                pRingBufferData1st,  /* First ring buffer segment. */
3857
                                                0                 ); /* Use all available channels. */
3858

    
3859
            /* If a second ring buffer segment is required. */
3860
            if( lRingBufferSize2nd ) {
3861
                /* Set number of frames to be copied to the ring buffer. */
3862
                PaUtil_Set2ndOutputFrameCount( pBp, lRingBufferSize2nd );
3863
                /* Setup ring buffer access. */
3864
                PaUtil_Set2ndInterleavedOutputChannels(pBp               ,  /* Buffer processor. */
3865
                                                       0                 ,  /* The first channel's index. */
3866
                                                       pRingBufferData2nd,  /* Second ring buffer segment. */
3867
                                                       0                 ); /* Use all available channels. */
3868
            }
3869

    
3870
            /* Let the buffer processor handle "copy and conversion" and
3871
               update the ring buffer indices manually. */
3872
            lFramesCopied = PaUtil_CopyOutput( pBp, &userBuffer, lFramesPerBlock );
3873
            PaUtil_AdvanceRingBufferWriteIndex( pRb, lFramesCopied );
3874

    
3875
            /* Decrease number of unprocessed frames. */
3876
            lFramesRemaining -= lFramesCopied;
3877

    
3878
        } /* Continue with the next data chunk. */
3879
        while( lFramesRemaining );
3880

    
3881

    
3882
        /* If there has been an output underflow within the callback */
3883
        if( blockingState->outputUnderflowFlag )
3884
        {
3885
            blockingState->outputUnderflowFlag = FALSE;
3886

    
3887
            /* Return the corresponding error code. */
3888
            result = paOutputUnderflowed;
3889
        }
3890

    
3891
    } /* If this is not an output stream. */
3892
    else
3893
    {
3894
        result = paCanNotWriteToAnInputOnlyStream;
3895
    }
3896

    
3897
    return result;
3898
}
3899

    
3900

    
3901
static signed long GetStreamReadAvailable( PaStream* s )
3902
{
3903
    PaAsioStream *stream = (PaAsioStream*)s;
3904

    
3905
    /* Call buffer utility routine to get the number of available frames. */
3906
    return PaUtil_GetRingBufferReadAvailable( &stream->blockingState->readRingBuffer );
3907
}
3908

    
3909

    
3910
static signed long GetStreamWriteAvailable( PaStream* s )
3911
{
3912
    PaAsioStream *stream = (PaAsioStream*)s;
3913

    
3914
    /* Call buffer utility routine to get the number of empty buffers. */
3915
    return PaUtil_GetRingBufferWriteAvailable( &stream->blockingState->writeRingBuffer );
3916
}
3917

    
3918

    
3919
/* This routine will be called by the PortAudio engine when audio is needed.
3920
** It may called at interrupt level on some machines so don't do anything
3921
** that could mess up the system like calling malloc() or free().
3922
*/
3923
static int BlockingIoPaCallback(const void                     *inputBuffer    ,
3924
                                      void                     *outputBuffer   ,
3925
                                      unsigned long             framesPerBuffer,
3926
                                const PaStreamCallbackTimeInfo *timeInfo       ,
3927
                                      PaStreamCallbackFlags     statusFlags    ,
3928
                                      void                     *userData       )
3929
{
3930
    PaError result = paNoError; /* Initial return value. */
3931
    PaAsioStream *stream = *(PaAsioStream**)userData; /* The PA ASIO stream. */
3932
    PaAsioStreamBlockingState *blockingState = stream->blockingState; /* Persume blockingState is valid, otherwise the callback wouldn't be running. */
3933

    
3934
    /* Get a pointer to the stream's blocking i/o buffer processor. */
3935
    PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor;
3936
    PaUtilRingBuffer      *pRb = NULL;
3937

    
3938
    /* If output data has been requested. */
3939
    if( stream->outputChannelCount )
3940
    {
3941
        /* If the callback input argument signalizes a output underflow,
3942
           make sure the WriteStream() function knows about it, too! */
3943
        if( statusFlags & paOutputUnderflowed ) {
3944
            blockingState->outputUnderflowFlag = TRUE;
3945
        }
3946

    
3947
        /* Access the corresponding ring buffer. */
3948
        pRb = &blockingState->writeRingBuffer;
3949

    
3950
        /* If the blocking i/o buffer contains enough output data, */
3951
        if( PaUtil_GetRingBufferReadAvailable(pRb) >= (long) framesPerBuffer )
3952
        {
3953
            /* Extract the requested data from the ring buffer. */
3954
            PaUtil_ReadRingBuffer( pRb, outputBuffer, framesPerBuffer );
3955
        }
3956
        else /* If no output data is available :-( */
3957
        {
3958
            /* Signalize a write-buffer underflow. */
3959
            blockingState->outputUnderflowFlag = TRUE;
3960

    
3961
            /* Fill the output buffer with silence. */
3962
            (*pBp->outputZeroer)( outputBuffer, 1, pBp->outputChannelCount * framesPerBuffer );
3963

    
3964
            /* If playback is to be stopped */
3965
            if( blockingState->stopFlag && PaUtil_GetRingBufferReadAvailable(pRb) < (long) framesPerBuffer )
3966
            {
3967
                /* Extract all the remaining data from the ring buffer,
3968
                   whether it is a complete data block or not. */
3969
                PaUtil_ReadRingBuffer( pRb, outputBuffer, PaUtil_GetRingBufferReadAvailable(pRb) );
3970
            }
3971
        }
3972

    
3973
        /* Set blocking i/o event? */
3974
        if( blockingState->writeBuffersRequestedFlag && PaUtil_GetRingBufferWriteAvailable(pRb) >= (long) blockingState->writeBuffersRequested )
3975
        {
3976
            /* Reset buffer request. */
3977
            blockingState->writeBuffersRequestedFlag = FALSE;
3978
            blockingState->writeBuffersRequested     = 0;
3979
            /* Signalize that requested buffers are ready. */
3980
            SetEvent( blockingState->writeBuffersReadyEvent );
3981
            /* What do we do if SetEvent() returns zero, i.e. the event
3982
               could not be set? How to return errors from within the
3983
               callback? - S.Fischer */
3984
        }
3985
    }
3986

    
3987
    /* If input data has been supplied. */
3988
    if( stream->inputChannelCount )
3989
    {
3990
        /* If the callback input argument signalizes a input overflow,
3991
           make sure the ReadStream() function knows about it, too! */
3992
        if( statusFlags & paInputOverflowed ) {
3993
            blockingState->inputOverflowFlag = TRUE;
3994
        }
3995

    
3996
        /* Access the corresponding ring buffer. */
3997
        pRb = &blockingState->readRingBuffer;
3998

    
3999
        /* If the blocking i/o buffer contains not enough input buffers */
4000
        if( PaUtil_GetRingBufferWriteAvailable(pRb) < (long) framesPerBuffer )
4001
        {
4002
            /* Signalize a read-buffer overflow. */
4003
            blockingState->inputOverflowFlag = TRUE;
4004

    
4005
            /* Remove some old data frames from the buffer. */
4006
            PaUtil_AdvanceRingBufferReadIndex( pRb, framesPerBuffer );
4007
        }
4008

    
4009
        /* Insert the current input data into the ring buffer. */
4010
        PaUtil_WriteRingBuffer( pRb, inputBuffer, framesPerBuffer );
4011

    
4012
        /* Set blocking i/o event? */
4013
        if( blockingState->readFramesRequestedFlag && PaUtil_GetRingBufferReadAvailable(pRb) >= (long) blockingState->readFramesRequested )
4014
        {
4015
            /* Reset buffer request. */
4016
            blockingState->readFramesRequestedFlag = FALSE;
4017
            blockingState->readFramesRequested     = 0;
4018
            /* Signalize that requested buffers are ready. */
4019
            SetEvent( blockingState->readFramesReadyEvent );
4020
            /* What do we do if SetEvent() returns zero, i.e. the event
4021
               could not be set? How to return errors from within the
4022
               callback? - S.Fischer */
4023
            /** @todo report an error with PA_DEBUG */
4024
        }
4025
    }
4026

    
4027
    return paContinue;
4028
}
4029

    
4030

    
4031
PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific )
4032
{
4033
    PaError result = paNoError;
4034
    PaUtilHostApiRepresentation *hostApi;
4035
    PaDeviceIndex hostApiDevice;
4036
    ASIODriverInfo asioDriverInfo;
4037
    ASIOError asioError;
4038
    int asioIsInitialized = 0;
4039
    PaAsioHostApiRepresentation *asioHostApi;
4040
    PaAsioDeviceInfo *asioDeviceInfo;
4041
    PaWinUtilComInitializationResult comInitializationResult;
4042

    
4043
    /* initialize COM again here, we might be in another thread */
4044
    result = PaWinUtil_CoInitialize( paASIO, &comInitializationResult );
4045
    if( result != paNoError )
4046
        return result;
4047

    
4048
    result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
4049
    if( result != paNoError )
4050
        goto error;
4051

    
4052
    result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
4053
    if( result != paNoError )
4054
        goto error;
4055

    
4056
    /*
4057
        In theory we could proceed if the currently open device was the same
4058
        one for which the control panel was requested, however  because the
4059
        window pointer is not available until this function is called we
4060
        currently need to call ASIOInit() again here, which of course can't be
4061
        done safely while a stream is open.
4062
    */
4063

    
4064
    asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
4065
    if( asioHostApi->openAsioDeviceIndex != paNoDevice )
4066
    {
4067
        result = paDeviceUnavailable;
4068
        goto error;
4069
    }
4070

    
4071
    asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
4072

    
4073
    if( !asioHostApi->asioDrivers->loadDriver( const_cast<char*>(asioDeviceInfo->commonDeviceInfo.name) ) )
4074
    {
4075
        result = paUnanticipatedHostError;
4076
        goto error;
4077
    }
4078

    
4079
    /* CRUCIAL!!! */
4080
    memset( &asioDriverInfo, 0, sizeof(ASIODriverInfo) );
4081
    asioDriverInfo.asioVersion = 2;
4082
    asioDriverInfo.sysRef = systemSpecific;
4083
    asioError = ASIOInit( &asioDriverInfo );
4084
    if( asioError != ASE_OK )
4085
    {
4086
        result = paUnanticipatedHostError;
4087
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
4088
        goto error;
4089
    }
4090
    else
4091
    {
4092
        asioIsInitialized = 1;
4093
    }
4094

    
4095
PA_DEBUG(("PaAsio_ShowControlPanel: ASIOInit(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
4096
PA_DEBUG(("asioVersion: ASIOInit(): %ld\n",   asioDriverInfo.asioVersion )); 
4097
PA_DEBUG(("driverVersion: ASIOInit(): %ld\n", asioDriverInfo.driverVersion )); 
4098
PA_DEBUG(("Name: ASIOInit(): %s\n",           asioDriverInfo.name )); 
4099
PA_DEBUG(("ErrorMessage: ASIOInit(): %s\n",   asioDriverInfo.errorMessage )); 
4100

    
4101
    asioError = ASIOControlPanel();
4102
    if( asioError != ASE_OK )
4103
    {
4104
        PA_DEBUG(("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
4105
        result = paUnanticipatedHostError;
4106
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
4107
        goto error;
4108
    }
4109

    
4110
PA_DEBUG(("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
4111

    
4112
    asioError = ASIOExit();
4113
    if( asioError != ASE_OK )
4114
    {
4115
        result = paUnanticipatedHostError;
4116
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
4117
        asioIsInitialized = 0;
4118
        goto error;
4119
    }
4120

    
4121
PA_DEBUG(("PaAsio_ShowControlPanel: ASIOExit(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
4122

    
4123
    return result;
4124

    
4125
error:
4126
    if( asioIsInitialized )
4127
        {
4128
                ASIOExit();
4129
        }
4130

    
4131
    PaWinUtil_CoUninitialize( paASIO, &comInitializationResult );
4132

    
4133
    return result;
4134
}
4135

    
4136

    
4137
PaError PaAsio_GetInputChannelName( PaDeviceIndex device, int channelIndex,
4138
        const char** channelName )
4139
{
4140
    PaError result = paNoError;
4141
    PaUtilHostApiRepresentation *hostApi;
4142
    PaDeviceIndex hostApiDevice;
4143
    PaAsioDeviceInfo *asioDeviceInfo;
4144

    
4145

    
4146
    result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
4147
    if( result != paNoError )
4148
        goto error;
4149

    
4150
    result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
4151
    if( result != paNoError )
4152
        goto error;
4153

    
4154
    asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
4155

    
4156
    if( channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxInputChannels ){
4157
        result = paInvalidChannelCount;
4158
        goto error;
4159
    }
4160

    
4161
    *channelName = asioDeviceInfo->asioChannelInfos[channelIndex].name;
4162

    
4163
    return paNoError;
4164
    
4165
error:
4166
    return result;
4167
}
4168

    
4169

    
4170
PaError PaAsio_GetOutputChannelName( PaDeviceIndex device, int channelIndex,
4171
        const char** channelName )
4172
{
4173
    PaError result = paNoError;
4174
    PaUtilHostApiRepresentation *hostApi;
4175
    PaDeviceIndex hostApiDevice;
4176
    PaAsioDeviceInfo *asioDeviceInfo;
4177

    
4178

    
4179
    result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
4180
    if( result != paNoError )
4181
        goto error;
4182

    
4183
    result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
4184
    if( result != paNoError )
4185
        goto error;
4186

    
4187
    asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
4188

    
4189
    if( channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxOutputChannels ){
4190
        result = paInvalidChannelCount;
4191
        goto error;
4192
    }
4193

    
4194
    *channelName = asioDeviceInfo->asioChannelInfos[
4195
            asioDeviceInfo->commonDeviceInfo.maxInputChannels + channelIndex].name;
4196

    
4197
    return paNoError;
4198
    
4199
error:
4200
    return result;
4201
}
4202

    
4203

    
4204
/* NOTE: the following functions are ASIO-stream specific, and are called directly
4205
    by client code. We need to check for many more error conditions here because
4206
    we don't have the benefit of pa_front.c's parameter checking.
4207
*/
4208

    
4209
static PaError GetAsioStreamPointer( PaAsioStream **stream, PaStream *s )
4210
{
4211
    PaError result;
4212
    PaUtilHostApiRepresentation *hostApi;
4213
    PaAsioHostApiRepresentation *asioHostApi;
4214
    
4215
    result = PaUtil_ValidateStreamPointer( s );
4216
    if( result != paNoError )
4217
        return result;
4218

    
4219
    result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
4220
    if( result != paNoError )
4221
        return result;
4222

    
4223
    asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
4224
    
4225
    if( PA_STREAM_REP( s )->streamInterface == &asioHostApi->callbackStreamInterface
4226
            || PA_STREAM_REP( s )->streamInterface == &asioHostApi->blockingStreamInterface )
4227
    {
4228
        /* s is an ASIO  stream */
4229
        *stream = (PaAsioStream *)s;
4230
        return paNoError;
4231
    }
4232
    else
4233
    {
4234
        return paIncompatibleStreamHostApi;
4235
    }
4236
}
4237

    
4238

    
4239
PaError PaAsio_SetStreamSampleRate( PaStream* s, double sampleRate )
4240
{
4241
    PaAsioStream *stream;
4242
    PaError result = GetAsioStreamPointer( &stream, s );
4243
    if( result != paNoError )
4244
        return result;
4245

    
4246
    if( stream != theAsioStream )
4247
        return paBadStreamPtr;
4248

    
4249
    return ValidateAndSetSampleRate( sampleRate );
4250
}
4251