~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/third_party/portaudio/src/hostapi/asio/pa_asio.cpp

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: pa_asio.cpp 1416 2009-06-16 16:12:41Z rossb $
 
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
    @todo implement host api specific extension to set i/o buffer sizes in frames
 
83
 
 
84
    @todo review ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable
 
85
 
 
86
    @todo review Blocking i/o latency computations in OpenStream(), changing ring 
 
87
          buffer to a non-power-of-two structure could reduce blocking i/o latency.
 
88
 
 
89
    @todo implement IsFormatSupported
 
90
 
 
91
    @todo work out how to implement stream stoppage from callback and
 
92
            implement IsStreamActive properly. Stream stoppage could be implemented
 
93
            using a high-priority thread blocked on an Event which is signalled
 
94
            by the callback. Or, we could just call ASIO stop from the callback
 
95
            and see what happens.
 
96
 
 
97
    @todo rigorously check asio return codes and convert to pa error codes
 
98
 
 
99
    @todo Different channels of a multichannel stream can have different sample
 
100
            formats, but we assume that all are the same as the first channel for now.
 
101
            Fixing this will require the block processor to maintain per-channel
 
102
            conversion functions - could get nasty.
 
103
 
 
104
    @todo investigate whether the asio processNow flag needs to be honoured
 
105
 
 
106
    @todo handle asioMessages() callbacks in a useful way, or at least document
 
107
            what cases we don't handle.
 
108
 
 
109
    @todo miscellaneous other FIXMEs
 
110
 
 
111
    @todo provide an asio-specific method for setting the systems specific
 
112
        value (aka main window handle) - check that this matches the value
 
113
        passed to PaAsio_ShowControlPanel, or remove it entirely from
 
114
        PaAsio_ShowControlPanel. - this would allow PaAsio_ShowControlPanel
 
115
        to be called for the currently open stream (at present all streams
 
116
        must be closed).
 
117
*/
 
118
 
 
119
 
 
120
 
 
121
#include <stdio.h>
 
122
#include <assert.h>
 
123
#include <string.h>
 
124
//#include <values.h>
 
125
#include <new>
 
126
 
 
127
#include <windows.h>
 
128
#include <mmsystem.h>
 
129
 
 
130
#include "portaudio.h"
 
131
#include "pa_asio.h"
 
132
#include "pa_util.h"
 
133
#include "pa_allocation.h"
 
134
#include "pa_hostapi.h"
 
135
#include "pa_stream.h"
 
136
#include "pa_cpuload.h"
 
137
#include "pa_process.h"
 
138
#include "pa_debugprint.h"
 
139
#include "pa_ringbuffer.h"
 
140
 
 
141
/* This version of pa_asio.cpp is currently only targetted at Win32,
 
142
   It would require a few tweaks to work with pre-OS X Macintosh.
 
143
   To make configuration easier, we define WIN32 here to make sure
 
144
   that the ASIO SDK knows this is Win32.
 
145
*/
 
146
#ifndef WIN32
 
147
#define WIN32
 
148
#endif
 
149
 
 
150
#include "asiosys.h"
 
151
#include "asio.h"
 
152
#include "asiodrivers.h"
 
153
#include "iasiothiscallresolver.h"
 
154
 
 
155
/*
 
156
#if MAC
 
157
#include <Devices.h>
 
158
#include <Timer.h>
 
159
#include <Math64.h>
 
160
#else
 
161
*/
 
162
/*
 
163
#include <math.h>
 
164
#include <windows.h>
 
165
#include <mmsystem.h>
 
166
*/
 
167
/*
 
168
#endif
 
169
*/
 
170
 
 
171
 
 
172
/* external reference to ASIO SDK's asioDrivers.
 
173
 
 
174
 This is a bit messy because we want to explicitly manage 
 
175
 allocation/deallocation of this structure, but some layers of the SDK 
 
176
 which we currently use (eg the implementation in asio.cpp) still
 
177
 use this global version.
 
178
 
 
179
 For now we keep it in sync with our local instance in the host
 
180
 API representation structure, but later we should be able to remove
 
181
 all dependence on it.
 
182
*/
 
183
extern AsioDrivers* asioDrivers;
 
184
 
 
185
 
 
186
/* We are trying to be compatible with CARBON but this has not been thoroughly tested. */
 
187
/* not tested at all since new V19 code was introduced. */
 
188
#define CARBON_COMPATIBLE  (0)
 
189
 
 
190
 
 
191
/* prototypes for functions declared in this file */
 
192
 
 
193
extern "C" PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );
 
194
static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
 
195
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
 
196
                           PaStream** s,
 
197
                           const PaStreamParameters *inputParameters,
 
198
                           const PaStreamParameters *outputParameters,
 
199
                           double sampleRate,
 
200
                           unsigned long framesPerBuffer,
 
201
                           PaStreamFlags streamFlags,
 
202
                           PaStreamCallback *streamCallback,
 
203
                           void *userData );
 
204
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
 
205
                                  const PaStreamParameters *inputParameters,
 
206
                                  const PaStreamParameters *outputParameters,
 
207
                                  double sampleRate );
 
208
static PaError CloseStream( PaStream* stream );
 
209
static PaError StartStream( PaStream *stream );
 
210
static PaError StopStream( PaStream *stream );
 
211
static PaError AbortStream( PaStream *stream );
 
212
static PaError IsStreamStopped( PaStream *s );
 
213
static PaError IsStreamActive( PaStream *stream );
 
214
static PaTime GetStreamTime( PaStream *stream );
 
215
static double GetStreamCpuLoad( PaStream* stream );
 
216
static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
 
217
static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
 
218
static signed long GetStreamReadAvailable( PaStream* stream );
 
219
static signed long GetStreamWriteAvailable( PaStream* stream );
 
220
 
 
221
/* Blocking i/o callback function. */
 
222
static int BlockingIoPaCallback(const void                     *inputBuffer    ,
 
223
                                      void                     *outputBuffer   ,
 
224
                                      unsigned long             framesPerBuffer,
 
225
                                const PaStreamCallbackTimeInfo *timeInfo       ,
 
226
                                      PaStreamCallbackFlags     statusFlags    ,
 
227
                                      void                     *userData       );
 
228
 
 
229
/* our ASIO callback functions */
 
230
 
 
231
static void bufferSwitch(long index, ASIOBool processNow);
 
232
static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow);
 
233
static void sampleRateChanged(ASIOSampleRate sRate);
 
234
static long asioMessages(long selector, long value, void* message, double* opt);
 
235
 
 
236
static ASIOCallbacks asioCallbacks_ =
 
237
    { bufferSwitch, sampleRateChanged, asioMessages, bufferSwitchTimeInfo };
 
238
 
 
239
 
 
240
#define PA_ASIO_SET_LAST_HOST_ERROR( errorCode, errorText ) \
 
241
    PaUtil_SetLastHostErrorInfo( paASIO, errorCode, errorText )
 
242
 
 
243
 
 
244
static void PaAsio_SetLastSystemError( DWORD errorCode )
 
245
{
 
246
    LPVOID lpMsgBuf;
 
247
    FormatMessage(
 
248
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
 
249
        NULL,
 
250
        errorCode,
 
251
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
 
252
        (LPTSTR) &lpMsgBuf,
 
253
        0,
 
254
        NULL
 
255
    );
 
256
    PaUtil_SetLastHostErrorInfo( paASIO, errorCode, (const char*)lpMsgBuf );
 
257
    LocalFree( lpMsgBuf );
 
258
}
 
259
 
 
260
#define PA_ASIO_SET_LAST_SYSTEM_ERROR( errorCode ) \
 
261
    PaAsio_SetLastSystemError( errorCode )
 
262
 
 
263
 
 
264
static const char* PaAsio_GetAsioErrorText( ASIOError asioError )
 
265
{
 
266
    const char *result;
 
267
 
 
268
    switch( asioError ){
 
269
        case ASE_OK:
 
270
        case ASE_SUCCESS:           result = "Success"; break;
 
271
        case ASE_NotPresent:        result = "Hardware input or output is not present or available"; break;
 
272
        case ASE_HWMalfunction:     result = "Hardware is malfunctioning"; break;
 
273
        case ASE_InvalidParameter:  result = "Input parameter invalid"; break;
 
274
        case ASE_InvalidMode:       result = "Hardware is in a bad mode or used in a bad mode"; break;
 
275
        case ASE_SPNotAdvancing:    result = "Hardware is not running when sample position is inquired"; break;
 
276
        case ASE_NoClock:           result = "Sample clock or rate cannot be determined or is not present"; break;
 
277
        case ASE_NoMemory:          result = "Not enough memory for completing the request"; break;
 
278
        default:                    result = "Unknown ASIO error"; break;
 
279
    }
 
280
 
 
281
    return result;
 
282
}
 
283
 
 
284
 
 
285
#define PA_ASIO_SET_LAST_ASIO_ERROR( asioError ) \
 
286
    PaUtil_SetLastHostErrorInfo( paASIO, asioError, PaAsio_GetAsioErrorText( asioError ) )
 
287
 
 
288
 
 
289
 
 
290
 
 
291
// Atomic increment and decrement operations
 
292
#if MAC
 
293
    /* need to be implemented on Mac */
 
294
    inline long PaAsio_AtomicIncrement(volatile long* v) {return ++(*const_cast<long*>(v));}
 
295
    inline long PaAsio_AtomicDecrement(volatile long* v) {return --(*const_cast<long*>(v));}
 
296
#elif WINDOWS
 
297
    inline long PaAsio_AtomicIncrement(volatile long* v) {return InterlockedIncrement(const_cast<long*>(v));}
 
298
    inline long PaAsio_AtomicDecrement(volatile long* v) {return InterlockedDecrement(const_cast<long*>(v));}
 
299
#endif
 
300
 
 
301
 
 
302
 
 
303
typedef struct PaAsioDriverInfo
 
304
{
 
305
    ASIODriverInfo asioDriverInfo;
 
306
    long inputChannelCount, outputChannelCount;
 
307
    long bufferMinSize, bufferMaxSize, bufferPreferredSize, bufferGranularity;
 
308
    bool postOutput;
 
309
}
 
310
PaAsioDriverInfo;
 
311
 
 
312
 
 
313
/* PaAsioHostApiRepresentation - host api datastructure specific to this implementation */
 
314
 
 
315
typedef struct
 
316
{
 
317
    PaUtilHostApiRepresentation inheritedHostApiRep;
 
318
    PaUtilStreamInterface callbackStreamInterface;
 
319
    PaUtilStreamInterface blockingStreamInterface;
 
320
 
 
321
    PaUtilAllocationGroup *allocations;
 
322
 
 
323
    AsioDrivers *asioDrivers;
 
324
    void *systemSpecific;
 
325
    
 
326
    /* the ASIO C API only allows one ASIO driver to be open at a time,
 
327
        so we keep track of whether we have the driver open here, and
 
328
        use this information to return errors from OpenStream if the
 
329
        driver is already open.
 
330
 
 
331
        openAsioDeviceIndex will be PaNoDevice if there is no device open
 
332
        and a valid pa_asio (not global) device index otherwise.
 
333
 
 
334
        openAsioDriverInfo is populated with the driver info for the
 
335
        currently open device (if any)
 
336
    */
 
337
    PaDeviceIndex openAsioDeviceIndex;
 
338
    PaAsioDriverInfo openAsioDriverInfo;
 
339
}
 
340
PaAsioHostApiRepresentation;
 
341
 
 
342
 
 
343
/*
 
344
    Retrieve <driverCount> driver names from ASIO, returned in a char**
 
345
    allocated in <group>.
 
346
*/
 
347
static char **GetAsioDriverNames( PaAsioHostApiRepresentation *asioHostApi, PaUtilAllocationGroup *group, long driverCount )
 
348
{
 
349
    char **result = 0;
 
350
    int i;
 
351
 
 
352
    result =(char**)PaUtil_GroupAllocateMemory(
 
353
            group, sizeof(char*) * driverCount );
 
354
    if( !result )
 
355
        goto error;
 
356
 
 
357
    result[0] = (char*)PaUtil_GroupAllocateMemory(
 
358
            group, 32 * driverCount );
 
359
    if( !result[0] )
 
360
        goto error;
 
361
 
 
362
    for( i=0; i<driverCount; ++i )
 
363
        result[i] = result[0] + (32 * i);
 
364
 
 
365
    asioHostApi->asioDrivers->getDriverNames( result, driverCount );
 
366
 
 
367
error:
 
368
    return result;
 
369
}
 
370
 
 
371
 
 
372
static PaSampleFormat AsioSampleTypeToPaNativeSampleFormat(ASIOSampleType type)
 
373
{
 
374
    switch (type) {
 
375
        case ASIOSTInt16MSB:
 
376
        case ASIOSTInt16LSB:
 
377
                return paInt16;
 
378
 
 
379
        case ASIOSTFloat32MSB:
 
380
        case ASIOSTFloat32LSB:
 
381
        case ASIOSTFloat64MSB:
 
382
        case ASIOSTFloat64LSB:
 
383
                return paFloat32;
 
384
 
 
385
        case ASIOSTInt32MSB:
 
386
        case ASIOSTInt32LSB:
 
387
        case ASIOSTInt32MSB16:
 
388
        case ASIOSTInt32LSB16:
 
389
        case ASIOSTInt32MSB18:
 
390
        case ASIOSTInt32MSB20:
 
391
        case ASIOSTInt32MSB24:
 
392
        case ASIOSTInt32LSB18:
 
393
        case ASIOSTInt32LSB20:
 
394
        case ASIOSTInt32LSB24:
 
395
                return paInt32;
 
396
 
 
397
        case ASIOSTInt24MSB:
 
398
        case ASIOSTInt24LSB:
 
399
                return paInt24;
 
400
 
 
401
        default:
 
402
                return paCustomFormat;
 
403
    }
 
404
}
 
405
 
 
406
void AsioSampleTypeLOG(ASIOSampleType type)
 
407
{
 
408
    switch (type) {
 
409
        case ASIOSTInt16MSB:  PA_DEBUG(("ASIOSTInt16MSB\n"));  break;
 
410
        case ASIOSTInt16LSB:  PA_DEBUG(("ASIOSTInt16LSB\n"));  break;
 
411
        case ASIOSTFloat32MSB:PA_DEBUG(("ASIOSTFloat32MSB\n"));break;
 
412
        case ASIOSTFloat32LSB:PA_DEBUG(("ASIOSTFloat32LSB\n"));break;
 
413
        case ASIOSTFloat64MSB:PA_DEBUG(("ASIOSTFloat64MSB\n"));break;
 
414
        case ASIOSTFloat64LSB:PA_DEBUG(("ASIOSTFloat64LSB\n"));break;
 
415
        case ASIOSTInt32MSB:  PA_DEBUG(("ASIOSTInt32MSB\n"));  break;
 
416
        case ASIOSTInt32LSB:  PA_DEBUG(("ASIOSTInt32LSB\n"));  break;
 
417
        case ASIOSTInt32MSB16:PA_DEBUG(("ASIOSTInt32MSB16\n"));break;
 
418
        case ASIOSTInt32LSB16:PA_DEBUG(("ASIOSTInt32LSB16\n"));break;
 
419
        case ASIOSTInt32MSB18:PA_DEBUG(("ASIOSTInt32MSB18\n"));break;
 
420
        case ASIOSTInt32MSB20:PA_DEBUG(("ASIOSTInt32MSB20\n"));break;
 
421
        case ASIOSTInt32MSB24:PA_DEBUG(("ASIOSTInt32MSB24\n"));break;
 
422
        case ASIOSTInt32LSB18:PA_DEBUG(("ASIOSTInt32LSB18\n"));break;
 
423
        case ASIOSTInt32LSB20:PA_DEBUG(("ASIOSTInt32LSB20\n"));break;
 
424
        case ASIOSTInt32LSB24:PA_DEBUG(("ASIOSTInt32LSB24\n"));break;
 
425
        case ASIOSTInt24MSB:  PA_DEBUG(("ASIOSTInt24MSB\n"));  break;
 
426
        case ASIOSTInt24LSB:  PA_DEBUG(("ASIOSTInt24LSB\n"));  break;
 
427
        default:              PA_DEBUG(("Custom Format%d\n",type));break;
 
428
 
 
429
    }
 
430
}
 
431
 
 
432
static int BytesPerAsioSample( ASIOSampleType sampleType )
 
433
{
 
434
    switch (sampleType) {
 
435
        case ASIOSTInt16MSB:
 
436
        case ASIOSTInt16LSB:
 
437
            return 2;
 
438
 
 
439
        case ASIOSTFloat64MSB:
 
440
        case ASIOSTFloat64LSB:
 
441
            return 8;
 
442
 
 
443
        case ASIOSTFloat32MSB:
 
444
        case ASIOSTFloat32LSB:
 
445
        case ASIOSTInt32MSB:
 
446
        case ASIOSTInt32LSB:
 
447
        case ASIOSTInt32MSB16:
 
448
        case ASIOSTInt32LSB16:
 
449
        case ASIOSTInt32MSB18:
 
450
        case ASIOSTInt32MSB20:
 
451
        case ASIOSTInt32MSB24:
 
452
        case ASIOSTInt32LSB18:
 
453
        case ASIOSTInt32LSB20:
 
454
        case ASIOSTInt32LSB24:
 
455
            return 4;
 
456
 
 
457
        case ASIOSTInt24MSB:
 
458
        case ASIOSTInt24LSB:
 
459
            return 3;
 
460
 
 
461
        default:
 
462
            return 0;
 
463
    }
 
464
}
 
465
 
 
466
 
 
467
static void Swap16( void *buffer, long shift, long count )
 
468
{
 
469
    unsigned short *p = (unsigned short*)buffer;
 
470
    unsigned short temp;
 
471
    (void) shift; /* unused parameter */
 
472
 
 
473
    while( count-- )
 
474
    {
 
475
        temp = *p;
 
476
        *p++ = (unsigned short)((temp<<8) | (temp>>8));
 
477
    }
 
478
}
 
479
 
 
480
static void Swap24( void *buffer, long shift, long count )
 
481
{
 
482
    unsigned char *p = (unsigned char*)buffer;
 
483
    unsigned char temp;
 
484
    (void) shift; /* unused parameter */
 
485
 
 
486
    while( count-- )
 
487
    {
 
488
        temp = *p;
 
489
        *p = *(p+2);
 
490
        *(p+2) = temp;
 
491
        p += 3;
 
492
    }
 
493
}
 
494
 
 
495
#define PA_SWAP32_( x ) ((x>>24) | ((x>>8)&0xFF00) | ((x<<8)&0xFF0000) | (x<<24));
 
496
 
 
497
static void Swap32( void *buffer, long shift, long count )
 
498
{
 
499
    unsigned long *p = (unsigned long*)buffer;
 
500
    unsigned long temp;
 
501
    (void) shift; /* unused parameter */
 
502
 
 
503
    while( count-- )
 
504
    {
 
505
        temp = *p;
 
506
        *p++ = PA_SWAP32_( temp);
 
507
    }
 
508
}
 
509
 
 
510
static void SwapShiftLeft32( void *buffer, long shift, long count )
 
511
{
 
512
    unsigned long *p = (unsigned long*)buffer;
 
513
    unsigned long temp;
 
514
 
 
515
    while( count-- )
 
516
    {
 
517
        temp = *p;
 
518
        temp = PA_SWAP32_( temp);
 
519
        *p++ = temp << shift;
 
520
    }
 
521
}
 
522
 
 
523
static void ShiftRightSwap32( void *buffer, long shift, long count )
 
524
{
 
525
    unsigned long *p = (unsigned long*)buffer;
 
526
    unsigned long temp;
 
527
 
 
528
    while( count-- )
 
529
    {
 
530
        temp = *p >> shift;
 
531
        *p++ = PA_SWAP32_( temp);
 
532
    }
 
533
}
 
534
 
 
535
static void ShiftLeft32( void *buffer, long shift, long count )
 
536
{
 
537
    unsigned long *p = (unsigned long*)buffer;
 
538
    unsigned long temp;
 
539
 
 
540
    while( count-- )
 
541
    {
 
542
        temp = *p;
 
543
        *p++ = temp << shift;
 
544
    }
 
545
}
 
546
 
 
547
static void ShiftRight32( void *buffer, long shift, long count )
 
548
{
 
549
    unsigned long *p = (unsigned long*)buffer;
 
550
    unsigned long temp;
 
551
 
 
552
    while( count-- )
 
553
    {
 
554
        temp = *p;
 
555
        *p++ = temp >> shift;
 
556
    }
 
557
}
 
558
 
 
559
#define PA_SWAP_( x, y ) temp=x; x = y; y = temp;
 
560
 
 
561
static void Swap64ConvertFloat64ToFloat32( void *buffer, long shift, long count )
 
562
{
 
563
    double *in = (double*)buffer;
 
564
    float *out = (float*)buffer;
 
565
    unsigned char *p;
 
566
    unsigned char temp;
 
567
    (void) shift; /* unused parameter */
 
568
 
 
569
    while( count-- )
 
570
    {
 
571
        p = (unsigned char*)in;
 
572
        PA_SWAP_( p[0], p[7] );
 
573
        PA_SWAP_( p[1], p[6] );
 
574
        PA_SWAP_( p[2], p[5] );
 
575
        PA_SWAP_( p[3], p[4] );
 
576
 
 
577
        *out++ = (float) (*in++);
 
578
    }
 
579
}
 
580
 
 
581
static void ConvertFloat64ToFloat32( void *buffer, long shift, long count )
 
582
{
 
583
    double *in = (double*)buffer;
 
584
    float *out = (float*)buffer;
 
585
    (void) shift; /* unused parameter */
 
586
 
 
587
    while( count-- )
 
588
        *out++ = (float) (*in++);
 
589
}
 
590
 
 
591
static void ConvertFloat32ToFloat64Swap64( void *buffer, long shift, long count )
 
592
{
 
593
    float *in = ((float*)buffer) + (count-1);
 
594
    double *out = ((double*)buffer) + (count-1);
 
595
    unsigned char *p;
 
596
    unsigned char temp;
 
597
    (void) shift; /* unused parameter */
 
598
 
 
599
    while( count-- )
 
600
    {
 
601
        *out = *in--;
 
602
 
 
603
        p = (unsigned char*)out;
 
604
        PA_SWAP_( p[0], p[7] );
 
605
        PA_SWAP_( p[1], p[6] );
 
606
        PA_SWAP_( p[2], p[5] );
 
607
        PA_SWAP_( p[3], p[4] );
 
608
 
 
609
        out--;
 
610
    }
 
611
}
 
612
 
 
613
static void ConvertFloat32ToFloat64( void *buffer, long shift, long count )
 
614
{
 
615
    float *in = ((float*)buffer) + (count-1);
 
616
    double *out = ((double*)buffer) + (count-1);
 
617
    (void) shift; /* unused parameter */
 
618
 
 
619
    while( count-- )
 
620
        *out-- = *in--;
 
621
}
 
622
 
 
623
#ifdef MAC
 
624
#define PA_MSB_IS_NATIVE_
 
625
#undef PA_LSB_IS_NATIVE_
 
626
#endif
 
627
 
 
628
#ifdef WINDOWS
 
629
#undef PA_MSB_IS_NATIVE_
 
630
#define PA_LSB_IS_NATIVE_
 
631
#endif
 
632
 
 
633
typedef void PaAsioBufferConverter( void *, long, long );
 
634
 
 
635
static void SelectAsioToPaConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift )
 
636
{
 
637
    *shift = 0;
 
638
    *converter = 0;
 
639
 
 
640
    switch (type) {
 
641
        case ASIOSTInt16MSB:
 
642
            /* dest: paInt16, no conversion necessary, possible byte swap*/
 
643
            #ifdef PA_LSB_IS_NATIVE_
 
644
                *converter = Swap16;
 
645
            #endif
 
646
            break;
 
647
        case ASIOSTInt16LSB:
 
648
            /* dest: paInt16, no conversion necessary, possible byte swap*/
 
649
            #ifdef PA_MSB_IS_NATIVE_
 
650
                *converter = Swap16;
 
651
            #endif
 
652
            break;
 
653
        case ASIOSTFloat32MSB:
 
654
            /* dest: paFloat32, no conversion necessary, possible byte swap*/
 
655
            #ifdef PA_LSB_IS_NATIVE_
 
656
                *converter = Swap32;
 
657
            #endif
 
658
            break;
 
659
        case ASIOSTFloat32LSB:
 
660
            /* dest: paFloat32, no conversion necessary, possible byte swap*/
 
661
            #ifdef PA_MSB_IS_NATIVE_
 
662
                *converter = Swap32;
 
663
            #endif
 
664
            break;
 
665
        case ASIOSTFloat64MSB:
 
666
            /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
 
667
            #ifdef PA_LSB_IS_NATIVE_
 
668
                *converter = Swap64ConvertFloat64ToFloat32;
 
669
            #else
 
670
                *converter = ConvertFloat64ToFloat32;
 
671
            #endif
 
672
            break;
 
673
        case ASIOSTFloat64LSB:
 
674
            /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
 
675
            #ifdef PA_MSB_IS_NATIVE_
 
676
                *converter = Swap64ConvertFloat64ToFloat32;
 
677
            #else
 
678
                *converter = ConvertFloat64ToFloat32;
 
679
            #endif
 
680
            break;
 
681
        case ASIOSTInt32MSB:
 
682
            /* dest: paInt32, no conversion necessary, possible byte swap */
 
683
            #ifdef PA_LSB_IS_NATIVE_
 
684
                *converter = Swap32;
 
685
            #endif
 
686
            break;
 
687
        case ASIOSTInt32LSB:
 
688
            /* dest: paInt32, no conversion necessary, possible byte swap */
 
689
            #ifdef PA_MSB_IS_NATIVE_
 
690
                *converter = Swap32;
 
691
            #endif
 
692
            break;
 
693
        case ASIOSTInt32MSB16:
 
694
            /* dest: paInt32, 16 bit shift, possible byte swap */
 
695
            #ifdef PA_LSB_IS_NATIVE_
 
696
                *converter = SwapShiftLeft32;
 
697
            #else
 
698
                *converter = ShiftLeft32;
 
699
            #endif
 
700
            *shift = 16;
 
701
            break;
 
702
        case ASIOSTInt32MSB18:
 
703
            /* dest: paInt32, 14 bit shift, possible byte swap */
 
704
            #ifdef PA_LSB_IS_NATIVE_
 
705
                *converter = SwapShiftLeft32;
 
706
            #else
 
707
                *converter = ShiftLeft32;
 
708
            #endif
 
709
            *shift = 14;
 
710
            break;
 
711
        case ASIOSTInt32MSB20:
 
712
            /* dest: paInt32, 12 bit shift, possible byte swap */
 
713
            #ifdef PA_LSB_IS_NATIVE_
 
714
                *converter = SwapShiftLeft32;
 
715
            #else
 
716
                *converter = ShiftLeft32;
 
717
            #endif
 
718
            *shift = 12;
 
719
            break;
 
720
        case ASIOSTInt32MSB24:
 
721
            /* dest: paInt32, 8 bit shift, possible byte swap */
 
722
            #ifdef PA_LSB_IS_NATIVE_
 
723
                *converter = SwapShiftLeft32;
 
724
            #else
 
725
                *converter = ShiftLeft32;
 
726
            #endif
 
727
            *shift = 8;
 
728
            break;
 
729
        case ASIOSTInt32LSB16:
 
730
            /* dest: paInt32, 16 bit shift, possible byte swap */
 
731
            #ifdef PA_MSB_IS_NATIVE_
 
732
                *converter = SwapShiftLeft32;
 
733
            #else
 
734
                *converter = ShiftLeft32;
 
735
            #endif
 
736
            *shift = 16;
 
737
            break;
 
738
        case ASIOSTInt32LSB18:
 
739
            /* dest: paInt32, 14 bit shift, possible byte swap */
 
740
            #ifdef PA_MSB_IS_NATIVE_
 
741
                *converter = SwapShiftLeft32;
 
742
            #else
 
743
                *converter = ShiftLeft32;
 
744
            #endif
 
745
            *shift = 14;
 
746
            break;
 
747
        case ASIOSTInt32LSB20:
 
748
            /* dest: paInt32, 12 bit shift, possible byte swap */
 
749
            #ifdef PA_MSB_IS_NATIVE_
 
750
                *converter = SwapShiftLeft32;
 
751
            #else
 
752
                *converter = ShiftLeft32;
 
753
            #endif
 
754
            *shift = 12;
 
755
            break;
 
756
        case ASIOSTInt32LSB24:
 
757
            /* dest: paInt32, 8 bit shift, possible byte swap */
 
758
            #ifdef PA_MSB_IS_NATIVE_
 
759
                *converter = SwapShiftLeft32;
 
760
            #else
 
761
                *converter = ShiftLeft32;
 
762
            #endif
 
763
            *shift = 8;
 
764
            break;
 
765
        case ASIOSTInt24MSB:
 
766
            /* dest: paInt24, no conversion necessary, possible byte swap */
 
767
            #ifdef PA_LSB_IS_NATIVE_
 
768
                *converter = Swap24;
 
769
            #endif
 
770
            break;
 
771
        case ASIOSTInt24LSB:
 
772
            /* dest: paInt24, no conversion necessary, possible byte swap */
 
773
            #ifdef PA_MSB_IS_NATIVE_
 
774
                *converter = Swap24;
 
775
            #endif
 
776
            break;
 
777
    }
 
778
}
 
779
 
 
780
 
 
781
static void SelectPaToAsioConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift )
 
782
{
 
783
    *shift = 0;
 
784
    *converter = 0;
 
785
 
 
786
    switch (type) {
 
787
        case ASIOSTInt16MSB:
 
788
            /* src: paInt16, no conversion necessary, possible byte swap*/
 
789
            #ifdef PA_LSB_IS_NATIVE_
 
790
                *converter = Swap16;
 
791
            #endif
 
792
            break;
 
793
        case ASIOSTInt16LSB:
 
794
            /* src: paInt16, no conversion necessary, possible byte swap*/
 
795
            #ifdef PA_MSB_IS_NATIVE_
 
796
                *converter = Swap16;
 
797
            #endif
 
798
            break;
 
799
        case ASIOSTFloat32MSB:
 
800
            /* src: paFloat32, no conversion necessary, possible byte swap*/
 
801
            #ifdef PA_LSB_IS_NATIVE_
 
802
                *converter = Swap32;
 
803
            #endif
 
804
            break;
 
805
        case ASIOSTFloat32LSB:
 
806
            /* src: paFloat32, no conversion necessary, possible byte swap*/
 
807
            #ifdef PA_MSB_IS_NATIVE_
 
808
                *converter = Swap32;
 
809
            #endif
 
810
            break;
 
811
        case ASIOSTFloat64MSB:
 
812
            /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
 
813
            #ifdef PA_LSB_IS_NATIVE_
 
814
                *converter = ConvertFloat32ToFloat64Swap64;
 
815
            #else
 
816
                *converter = ConvertFloat32ToFloat64;
 
817
            #endif
 
818
            break;
 
819
        case ASIOSTFloat64LSB:
 
820
            /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
 
821
            #ifdef PA_MSB_IS_NATIVE_
 
822
                *converter = ConvertFloat32ToFloat64Swap64;
 
823
            #else
 
824
                *converter = ConvertFloat32ToFloat64;
 
825
            #endif
 
826
            break;
 
827
        case ASIOSTInt32MSB:
 
828
            /* src: paInt32, no conversion necessary, possible byte swap */
 
829
            #ifdef PA_LSB_IS_NATIVE_
 
830
                *converter = Swap32;
 
831
            #endif
 
832
            break;
 
833
        case ASIOSTInt32LSB:
 
834
            /* src: paInt32, no conversion necessary, possible byte swap */
 
835
            #ifdef PA_MSB_IS_NATIVE_
 
836
                *converter = Swap32;
 
837
            #endif
 
838
            break;
 
839
        case ASIOSTInt32MSB16:
 
840
            /* src: paInt32, 16 bit shift, possible byte swap */
 
841
            #ifdef PA_LSB_IS_NATIVE_
 
842
                *converter = ShiftRightSwap32;
 
843
            #else
 
844
                *converter = ShiftRight32;
 
845
            #endif
 
846
            *shift = 16;
 
847
            break;
 
848
        case ASIOSTInt32MSB18:
 
849
            /* src: paInt32, 14 bit shift, possible byte swap */
 
850
            #ifdef PA_LSB_IS_NATIVE_
 
851
                *converter = ShiftRightSwap32;
 
852
            #else
 
853
                *converter = ShiftRight32;
 
854
            #endif
 
855
            *shift = 14;
 
856
            break;
 
857
        case ASIOSTInt32MSB20:
 
858
            /* src: paInt32, 12 bit shift, possible byte swap */
 
859
            #ifdef PA_LSB_IS_NATIVE_
 
860
                *converter = ShiftRightSwap32;
 
861
            #else
 
862
                *converter = ShiftRight32;
 
863
            #endif
 
864
            *shift = 12;
 
865
            break;
 
866
        case ASIOSTInt32MSB24:
 
867
            /* src: paInt32, 8 bit shift, possible byte swap */
 
868
            #ifdef PA_LSB_IS_NATIVE_
 
869
                *converter = ShiftRightSwap32;
 
870
            #else
 
871
                *converter = ShiftRight32;
 
872
            #endif
 
873
            *shift = 8;
 
874
            break;
 
875
        case ASIOSTInt32LSB16:
 
876
            /* src: paInt32, 16 bit shift, possible byte swap */
 
877
            #ifdef PA_MSB_IS_NATIVE_
 
878
                *converter = ShiftRightSwap32;
 
879
            #else
 
880
                *converter = ShiftRight32;
 
881
            #endif
 
882
            *shift = 16;
 
883
            break;
 
884
        case ASIOSTInt32LSB18:
 
885
            /* src: paInt32, 14 bit shift, possible byte swap */
 
886
            #ifdef PA_MSB_IS_NATIVE_
 
887
                *converter = ShiftRightSwap32;
 
888
            #else
 
889
                *converter = ShiftRight32;
 
890
            #endif
 
891
            *shift = 14;
 
892
            break;
 
893
        case ASIOSTInt32LSB20:
 
894
            /* src: paInt32, 12 bit shift, possible byte swap */
 
895
            #ifdef PA_MSB_IS_NATIVE_
 
896
                *converter = ShiftRightSwap32;
 
897
            #else
 
898
                *converter = ShiftRight32;
 
899
            #endif
 
900
            *shift = 12;
 
901
            break;
 
902
        case ASIOSTInt32LSB24:
 
903
            /* src: paInt32, 8 bit shift, possible byte swap */
 
904
            #ifdef PA_MSB_IS_NATIVE_
 
905
                *converter = ShiftRightSwap32;
 
906
            #else
 
907
                *converter = ShiftRight32;
 
908
            #endif
 
909
            *shift = 8;
 
910
            break;
 
911
        case ASIOSTInt24MSB:
 
912
            /* src: paInt24, no conversion necessary, possible byte swap */
 
913
            #ifdef PA_LSB_IS_NATIVE_
 
914
                *converter = Swap24;
 
915
            #endif
 
916
            break;
 
917
        case ASIOSTInt24LSB:
 
918
            /* src: paInt24, no conversion necessary, possible byte swap */
 
919
            #ifdef PA_MSB_IS_NATIVE_
 
920
                *converter = Swap24;
 
921
            #endif
 
922
            break;
 
923
    }
 
924
}
 
925
 
 
926
 
 
927
typedef struct PaAsioDeviceInfo
 
928
{
 
929
    PaDeviceInfo commonDeviceInfo;
 
930
    long minBufferSize;
 
931
    long maxBufferSize;
 
932
    long preferredBufferSize;
 
933
    long bufferGranularity;
 
934
 
 
935
    ASIOChannelInfo *asioChannelInfos;
 
936
}
 
937
PaAsioDeviceInfo;
 
938
 
 
939
 
 
940
PaError PaAsio_GetAvailableLatencyValues( PaDeviceIndex device,
 
941
        long *minLatency, long *maxLatency, long *preferredLatency, long *granularity )
 
942
{
 
943
    PaError result;
 
944
    PaUtilHostApiRepresentation *hostApi;
 
945
    PaDeviceIndex hostApiDevice;
 
946
 
 
947
    result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
 
948
 
 
949
    if( result == paNoError )
 
950
    {
 
951
        result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
 
952
 
 
953
        if( result == paNoError )
 
954
        {
 
955
            PaAsioDeviceInfo *asioDeviceInfo =
 
956
                    (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
 
957
 
 
958
            *minLatency = asioDeviceInfo->minBufferSize;
 
959
            *maxLatency = asioDeviceInfo->maxBufferSize;
 
960
            *preferredLatency = asioDeviceInfo->preferredBufferSize;
 
961
            *granularity = asioDeviceInfo->bufferGranularity;
 
962
        }
 
963
    }
 
964
 
 
965
    return result;
 
966
}
 
967
 
 
968
/* Unload whatever we loaded in LoadAsioDriver().
 
969
   Also balance the call to CoInitialize(0).
 
970
*/
 
971
static void UnloadAsioDriver( void )
 
972
{
 
973
        ASIOExit();
 
974
        CoUninitialize();
 
975
}
 
976
 
 
977
/*
 
978
    load the asio driver named by <driverName> and return statistics about
 
979
    the driver in info. If no error occurred, the driver will remain open
 
980
    and must be closed by the called by calling UnloadAsioDriver() - if an error
 
981
    is returned the driver will already be unloaded.
 
982
*/
 
983
static PaError LoadAsioDriver( PaAsioHostApiRepresentation *asioHostApi, const char *driverName,
 
984
        PaAsioDriverInfo *driverInfo, void *systemSpecific )
 
985
{
 
986
    PaError result = paNoError;
 
987
    ASIOError asioError;
 
988
    int asioIsInitialized = 0;
 
989
 
 
990
    /* 
 
991
        ASIO uses CoCreateInstance() to load a driver. That requires that
 
992
        CoInitialize(0) be called for every thread that loads a driver.
 
993
        It is OK to call CoInitialize(0) multiple times form one thread as long
 
994
        as it is balanced by a call to CoUninitialize(). See UnloadAsioDriver().
 
995
 
 
996
        The V18 version called CoInitialize() starting on 2/19/02.
 
997
        That was removed from PA V19 for unknown reasons.
 
998
        Phil Burk added it back on 6/27/08 so that JSyn would work.
 
999
    */
 
1000
        CoInitialize( 0 );
 
1001
 
 
1002
    if( !asioHostApi->asioDrivers->loadDriver( const_cast<char*>(driverName) ) )
 
1003
    {
 
1004
                /* If this returns an error then it might be because CoInitialize(0) was removed.
 
1005
                  It should be called right before this.
 
1006
            */
 
1007
        result = paUnanticipatedHostError;
 
1008
        PA_ASIO_SET_LAST_HOST_ERROR( 0, "Failed to load ASIO driver" );
 
1009
        goto error;
 
1010
    }
 
1011
 
 
1012
    memset( &driverInfo->asioDriverInfo, 0, sizeof(ASIODriverInfo) );
 
1013
    driverInfo->asioDriverInfo.asioVersion = 2;
 
1014
    driverInfo->asioDriverInfo.sysRef = systemSpecific;
 
1015
    if( (asioError = ASIOInit( &driverInfo->asioDriverInfo )) != ASE_OK )
 
1016
    {
 
1017
        result = paUnanticipatedHostError;
 
1018
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
 
1019
        goto error;
 
1020
    }
 
1021
    else
 
1022
    {
 
1023
        asioIsInitialized = 1;
 
1024
    }
 
1025
 
 
1026
    if( (asioError = ASIOGetChannels(&driverInfo->inputChannelCount,
 
1027
            &driverInfo->outputChannelCount)) != ASE_OK )
 
1028
    {
 
1029
        result = paUnanticipatedHostError;
 
1030
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
 
1031
        goto error;
 
1032
    }
 
1033
 
 
1034
    if( (asioError = ASIOGetBufferSize(&driverInfo->bufferMinSize,
 
1035
            &driverInfo->bufferMaxSize, &driverInfo->bufferPreferredSize,
 
1036
            &driverInfo->bufferGranularity)) != ASE_OK )
 
1037
    {
 
1038
        result = paUnanticipatedHostError;
 
1039
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
 
1040
        goto error;
 
1041
    }
 
1042
 
 
1043
    if( ASIOOutputReady() == ASE_OK )
 
1044
        driverInfo->postOutput = true;
 
1045
    else
 
1046
        driverInfo->postOutput = false;
 
1047
 
 
1048
    return result;
 
1049
 
 
1050
error:
 
1051
    if( asioIsInitialized )
 
1052
        {
 
1053
                ASIOExit();
 
1054
        }
 
1055
        CoUninitialize();
 
1056
    return result;
 
1057
}
 
1058
 
 
1059
 
 
1060
#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_     13   /* must be the same number of elements as in the array below */
 
1061
static ASIOSampleRate defaultSampleRateSearchOrder_[]
 
1062
     = {44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0,
 
1063
        192000.0, 16000.0, 12000.0, 11025.0, 9600.0, 8000.0 };
 
1064
 
 
1065
 
 
1066
/* we look up IsDebuggerPresent at runtime incase it isn't present (on Win95 for example) */
 
1067
typedef BOOL (WINAPI *IsDebuggerPresentPtr)(VOID);
 
1068
IsDebuggerPresentPtr IsDebuggerPresent_ = 0;
 
1069
//FARPROC IsDebuggerPresent_ = 0; // this is the current way to do it apparently according to davidv
 
1070
 
 
1071
PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
 
1072
{
 
1073
    PaError result = paNoError;
 
1074
    int i, driverCount;
 
1075
    PaAsioHostApiRepresentation *asioHostApi;
 
1076
    PaAsioDeviceInfo *deviceInfoArray;
 
1077
    char **names;
 
1078
    PaAsioDriverInfo paAsioDriverInfo;
 
1079
 
 
1080
    asioHostApi = (PaAsioHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaAsioHostApiRepresentation) );
 
1081
    if( !asioHostApi )
 
1082
    {
 
1083
        result = paInsufficientMemory;
 
1084
        goto error;
 
1085
    }
 
1086
 
 
1087
    asioHostApi->asioDrivers = 0; /* avoid surprises in our error handler below */
 
1088
 
 
1089
    asioHostApi->allocations = PaUtil_CreateAllocationGroup();
 
1090
    if( !asioHostApi->allocations )
 
1091
    {
 
1092
        result = paInsufficientMemory;
 
1093
        goto error;
 
1094
    }
 
1095
 
 
1096
    /* Allocate the AsioDrivers() driver list (class from ASIO SDK) */
 
1097
    try
 
1098
    {
 
1099
        asioHostApi->asioDrivers = new AsioDrivers(); /* calls CoInitialize(0) */
 
1100
    } 
 
1101
    catch (std::bad_alloc)
 
1102
    {
 
1103
        asioHostApi->asioDrivers = 0;
 
1104
    }
 
1105
    /* some implementations of new (ie MSVC, see http://support.microsoft.com/?kbid=167733)
 
1106
       don't throw std::bad_alloc, so we also explicitly test for a null return. */
 
1107
    if( asioHostApi->asioDrivers == 0 )
 
1108
    {
 
1109
        result = paInsufficientMemory;
 
1110
        goto error;
 
1111
    }
 
1112
 
 
1113
    asioDrivers = asioHostApi->asioDrivers; /* keep SDK global in sync until we stop depending on it */
 
1114
 
 
1115
    asioHostApi->systemSpecific = 0;
 
1116
    asioHostApi->openAsioDeviceIndex = paNoDevice;
 
1117
 
 
1118
    *hostApi = &asioHostApi->inheritedHostApiRep;
 
1119
    (*hostApi)->info.structVersion = 1;
 
1120
 
 
1121
    (*hostApi)->info.type = paASIO;
 
1122
    (*hostApi)->info.name = "ASIO";
 
1123
    (*hostApi)->info.deviceCount = 0;
 
1124
 
 
1125
    #ifdef WINDOWS
 
1126
        /* use desktop window as system specific ptr */
 
1127
        asioHostApi->systemSpecific = GetDesktopWindow();
 
1128
    #endif
 
1129
 
 
1130
    /* driverCount is the number of installed drivers - not necessarily
 
1131
        the number of installed physical devices. */
 
1132
    #if MAC
 
1133
        driverCount = asioHostApi->asioDrivers->getNumFragments();
 
1134
    #elif WINDOWS
 
1135
        driverCount = asioHostApi->asioDrivers->asioGetNumDev();
 
1136
    #endif
 
1137
 
 
1138
    if( driverCount > 0 )
 
1139
    {
 
1140
        names = GetAsioDriverNames( asioHostApi, asioHostApi->allocations, driverCount );
 
1141
        if( !names )
 
1142
        {
 
1143
            result = paInsufficientMemory;
 
1144
            goto error;
 
1145
        }
 
1146
 
 
1147
 
 
1148
        /* allocate enough space for all drivers, even if some aren't installed */
 
1149
 
 
1150
        (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
 
1151
                asioHostApi->allocations, sizeof(PaDeviceInfo*) * driverCount );
 
1152
        if( !(*hostApi)->deviceInfos )
 
1153
        {
 
1154
            result = paInsufficientMemory;
 
1155
            goto error;
 
1156
        }
 
1157
 
 
1158
        /* allocate all device info structs in a contiguous block */
 
1159
        deviceInfoArray = (PaAsioDeviceInfo*)PaUtil_GroupAllocateMemory(
 
1160
                asioHostApi->allocations, sizeof(PaAsioDeviceInfo) * driverCount );
 
1161
        if( !deviceInfoArray )
 
1162
        {
 
1163
            result = paInsufficientMemory;
 
1164
            goto error;
 
1165
        }
 
1166
 
 
1167
        IsDebuggerPresent_ = GetProcAddress( LoadLibrary( "Kernel32.dll" ), "IsDebuggerPresent" );
 
1168
 
 
1169
        for( i=0; i < driverCount; ++i )
 
1170
        {
 
1171
 
 
1172
            PA_DEBUG(("ASIO names[%d]:%s\n",i,names[i]));
 
1173
 
 
1174
            // Since portaudio opens ALL ASIO drivers, and no one else does that,
 
1175
            // we face fact that some drivers were not meant for it, drivers which act
 
1176
            // like shells on top of REAL drivers, for instance.
 
1177
            // so we get duplicate handles, locks and other problems.
 
1178
            // so lets NOT try to load any such wrappers. 
 
1179
            // The ones i [davidv] know of so far are:
 
1180
 
 
1181
            if (   strcmp (names[i],"ASIO DirectX Full Duplex Driver") == 0
 
1182
                || strcmp (names[i],"ASIO Multimedia Driver")          == 0
 
1183
                || strncmp(names[i],"Premiere",8)                      == 0   //"Premiere Elements Windows Sound 1.0"
 
1184
                || strncmp(names[i],"Adobe",5)                         == 0   //"Adobe Default Windows Sound 1.5"
 
1185
               )
 
1186
            {
 
1187
                PA_DEBUG(("BLACKLISTED!!!\n"));
 
1188
                continue;
 
1189
            }
 
1190
 
 
1191
 
 
1192
            if( IsDebuggerPresent_ && IsDebuggerPresent_() )  
 
1193
            {
 
1194
                /* ASIO Digidesign Driver uses PACE copy protection which quits out
 
1195
                   if a debugger is running. So we don't load it if a debugger is running. */
 
1196
                if( strcmp(names[i], "ASIO Digidesign Driver") == 0 )  
 
1197
                {
 
1198
                    PA_DEBUG(("BLACKLISTED!!! ASIO Digidesign Driver would quit the debugger\n"));  
 
1199
                    continue;  
 
1200
                }  
 
1201
            }  
 
1202
 
 
1203
 
 
1204
            /* Attempt to load the asio driver... */
 
1205
            if( LoadAsioDriver( asioHostApi, names[i], &paAsioDriverInfo, asioHostApi->systemSpecific ) == paNoError )
 
1206
            {
 
1207
                PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
 
1208
                PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo;
 
1209
 
 
1210
                deviceInfo->structVersion = 2;
 
1211
                deviceInfo->hostApi = hostApiIndex;
 
1212
 
 
1213
                deviceInfo->name = names[i];
 
1214
                PA_DEBUG(("PaAsio_Initialize: drv:%d name = %s\n",  i,deviceInfo->name));
 
1215
                PA_DEBUG(("PaAsio_Initialize: drv:%d inputChannels       = %d\n", i, paAsioDriverInfo.inputChannelCount));
 
1216
                PA_DEBUG(("PaAsio_Initialize: drv:%d outputChannels      = %d\n", i, paAsioDriverInfo.outputChannelCount));
 
1217
                PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMinSize       = %d\n", i, paAsioDriverInfo.bufferMinSize));
 
1218
                PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMaxSize       = %d\n", i, paAsioDriverInfo.bufferMaxSize));
 
1219
                PA_DEBUG(("PaAsio_Initialize: drv:%d bufferPreferredSize = %d\n", i, paAsioDriverInfo.bufferPreferredSize));
 
1220
                PA_DEBUG(("PaAsio_Initialize: drv:%d bufferGranularity   = %d\n", i, paAsioDriverInfo.bufferGranularity));
 
1221
 
 
1222
                deviceInfo->maxInputChannels  = paAsioDriverInfo.inputChannelCount;
 
1223
                deviceInfo->maxOutputChannels = paAsioDriverInfo.outputChannelCount;
 
1224
 
 
1225
                deviceInfo->defaultSampleRate = 0.;
 
1226
                bool foundDefaultSampleRate = false;
 
1227
                for( int j=0; j < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++j )
 
1228
                {
 
1229
                    ASIOError asioError = ASIOCanSampleRate( defaultSampleRateSearchOrder_[j] );
 
1230
                    if( asioError != ASE_NoClock && asioError != ASE_NotPresent )
 
1231
                    {
 
1232
                        deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[j];
 
1233
                        foundDefaultSampleRate = true;
 
1234
                        break;
 
1235
                    }
 
1236
                }
 
1237
 
 
1238
                PA_DEBUG(("PaAsio_Initialize: drv:%d defaultSampleRate = %f\n", i, deviceInfo->defaultSampleRate));
 
1239
 
 
1240
                if( foundDefaultSampleRate ){
 
1241
 
 
1242
                    /* calculate default latency values from bufferPreferredSize
 
1243
                        for default low latency, and bufferPreferredSize * 3
 
1244
                        for default high latency.
 
1245
                        use the default sample rate to convert from samples to
 
1246
                        seconds. Without knowing what sample rate the user will
 
1247
                        use this is the best we can do.
 
1248
                    */
 
1249
 
 
1250
                    double defaultLowLatency =
 
1251
                            paAsioDriverInfo.bufferPreferredSize / deviceInfo->defaultSampleRate;
 
1252
 
 
1253
                    deviceInfo->defaultLowInputLatency = defaultLowLatency;
 
1254
                    deviceInfo->defaultLowOutputLatency = defaultLowLatency;
 
1255
 
 
1256
                    long defaultHighLatencyBufferSize =
 
1257
                            paAsioDriverInfo.bufferPreferredSize * 3;
 
1258
 
 
1259
                    if( defaultHighLatencyBufferSize > paAsioDriverInfo.bufferMaxSize )
 
1260
                        defaultHighLatencyBufferSize = paAsioDriverInfo.bufferMaxSize;
 
1261
 
 
1262
                    double defaultHighLatency =
 
1263
                            defaultHighLatencyBufferSize / deviceInfo->defaultSampleRate;
 
1264
 
 
1265
                    if( defaultHighLatency < defaultLowLatency )
 
1266
                        defaultHighLatency = defaultLowLatency; /* just incase the driver returns something strange */ 
 
1267
                            
 
1268
                    deviceInfo->defaultHighInputLatency = defaultHighLatency;
 
1269
                    deviceInfo->defaultHighOutputLatency = defaultHighLatency;
 
1270
                    
 
1271
                }else{
 
1272
 
 
1273
                    deviceInfo->defaultLowInputLatency = 0.;
 
1274
                    deviceInfo->defaultLowOutputLatency = 0.;
 
1275
                    deviceInfo->defaultHighInputLatency = 0.;
 
1276
                    deviceInfo->defaultHighOutputLatency = 0.;
 
1277
                }
 
1278
 
 
1279
                PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowInputLatency = %f\n", i, deviceInfo->defaultLowInputLatency));
 
1280
                PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowOutputLatency = %f\n", i, deviceInfo->defaultLowOutputLatency));
 
1281
                PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighInputLatency = %f\n", i, deviceInfo->defaultHighInputLatency));
 
1282
                PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighOutputLatency = %f\n", i, deviceInfo->defaultHighOutputLatency));
 
1283
 
 
1284
                asioDeviceInfo->minBufferSize = paAsioDriverInfo.bufferMinSize;
 
1285
                asioDeviceInfo->maxBufferSize = paAsioDriverInfo.bufferMaxSize;
 
1286
                asioDeviceInfo->preferredBufferSize = paAsioDriverInfo.bufferPreferredSize;
 
1287
                asioDeviceInfo->bufferGranularity = paAsioDriverInfo.bufferGranularity;
 
1288
 
 
1289
 
 
1290
                asioDeviceInfo->asioChannelInfos = (ASIOChannelInfo*)PaUtil_GroupAllocateMemory(
 
1291
                        asioHostApi->allocations,
 
1292
                        sizeof(ASIOChannelInfo) * (deviceInfo->maxInputChannels
 
1293
                                + deviceInfo->maxOutputChannels) );
 
1294
                if( !asioDeviceInfo->asioChannelInfos )
 
1295
                {
 
1296
                    result = paInsufficientMemory;
 
1297
                    goto error_unload;
 
1298
                }
 
1299
 
 
1300
                int a;
 
1301
 
 
1302
                for( a=0; a < deviceInfo->maxInputChannels; ++a ){
 
1303
                    asioDeviceInfo->asioChannelInfos[a].channel = a;
 
1304
                    asioDeviceInfo->asioChannelInfos[a].isInput = ASIOTrue;
 
1305
                    ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[a] );
 
1306
                    if( asioError != ASE_OK )
 
1307
                    {
 
1308
                        result = paUnanticipatedHostError;
 
1309
                        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
 
1310
                        goto error_unload;
 
1311
                    }
 
1312
                }
 
1313
 
 
1314
                for( a=0; a < deviceInfo->maxOutputChannels; ++a ){
 
1315
                    int b = deviceInfo->maxInputChannels + a;
 
1316
                    asioDeviceInfo->asioChannelInfos[b].channel = a;
 
1317
                    asioDeviceInfo->asioChannelInfos[b].isInput = ASIOFalse;
 
1318
                    ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[b] );
 
1319
                    if( asioError != ASE_OK )
 
1320
                    {
 
1321
                        result = paUnanticipatedHostError;
 
1322
                        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
 
1323
                        goto error_unload;
 
1324
                    }
 
1325
                }
 
1326
 
 
1327
 
 
1328
                /* unload the driver */
 
1329
                UnloadAsioDriver();
 
1330
 
 
1331
                (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
 
1332
                ++(*hostApi)->info.deviceCount;
 
1333
            }
 
1334
        }
 
1335
    }
 
1336
 
 
1337
    if( (*hostApi)->info.deviceCount > 0 )
 
1338
    {
 
1339
        (*hostApi)->info.defaultInputDevice = 0;
 
1340
        (*hostApi)->info.defaultOutputDevice = 0;
 
1341
    }
 
1342
    else
 
1343
    {
 
1344
        (*hostApi)->info.defaultInputDevice = paNoDevice;
 
1345
        (*hostApi)->info.defaultOutputDevice = paNoDevice;
 
1346
    }
 
1347
 
 
1348
 
 
1349
    (*hostApi)->Terminate = Terminate;
 
1350
    (*hostApi)->OpenStream = OpenStream;
 
1351
    (*hostApi)->IsFormatSupported = IsFormatSupported;
 
1352
 
 
1353
    PaUtil_InitializeStreamInterface( &asioHostApi->callbackStreamInterface, CloseStream, StartStream,
 
1354
                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
 
1355
                                      GetStreamTime, GetStreamCpuLoad,
 
1356
                                      PaUtil_DummyRead, PaUtil_DummyWrite,
 
1357
                                      PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
 
1358
 
 
1359
    PaUtil_InitializeStreamInterface( &asioHostApi->blockingStreamInterface, CloseStream, StartStream,
 
1360
                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
 
1361
                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
 
1362
                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
 
1363
 
 
1364
    return result;
 
1365
 
 
1366
error_unload:
 
1367
        UnloadAsioDriver();
 
1368
 
 
1369
error:
 
1370
    if( asioHostApi )
 
1371
    {
 
1372
        if( asioHostApi->allocations )
 
1373
        {
 
1374
            PaUtil_FreeAllAllocations( asioHostApi->allocations );
 
1375
            PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
 
1376
        }
 
1377
 
 
1378
        delete asioHostApi->asioDrivers;
 
1379
        asioDrivers = 0; /* keep SDK global in sync until we stop depending on it */
 
1380
 
 
1381
        PaUtil_FreeMemory( asioHostApi );
 
1382
    }
 
1383
    return result;
 
1384
}
 
1385
 
 
1386
 
 
1387
static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
 
1388
{
 
1389
    PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
 
1390
 
 
1391
    /*
 
1392
        IMPLEMENT ME:
 
1393
            - clean up any resources not handled by the allocation group (need to review if there are any)
 
1394
    */
 
1395
 
 
1396
    if( asioHostApi->allocations )
 
1397
    {
 
1398
        PaUtil_FreeAllAllocations( asioHostApi->allocations );
 
1399
        PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
 
1400
    }
 
1401
 
 
1402
    delete asioHostApi->asioDrivers; /* calls CoUninitialize() */
 
1403
    asioDrivers = 0; /* keep SDK global in sync until we stop depending on it */
 
1404
 
 
1405
    PaUtil_FreeMemory( asioHostApi );
 
1406
}
 
1407
 
 
1408
 
 
1409
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
 
1410
                                  const PaStreamParameters *inputParameters,
 
1411
                                  const PaStreamParameters *outputParameters,
 
1412
                                  double sampleRate )
 
1413
{
 
1414
    PaError result = paNoError;
 
1415
    PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
 
1416
    PaAsioDriverInfo *driverInfo = &asioHostApi->openAsioDriverInfo;
 
1417
    int inputChannelCount, outputChannelCount;
 
1418
    PaSampleFormat inputSampleFormat, outputSampleFormat;
 
1419
    PaDeviceIndex asioDeviceIndex;                                  
 
1420
    ASIOError asioError;
 
1421
    
 
1422
    if( inputParameters && outputParameters )
 
1423
    {
 
1424
        /* full duplex ASIO stream must use the same device for input and output */
 
1425
 
 
1426
        if( inputParameters->device != outputParameters->device )
 
1427
            return paBadIODeviceCombination;
 
1428
    }
 
1429
    
 
1430
    if( inputParameters )
 
1431
    {
 
1432
        inputChannelCount = inputParameters->channelCount;
 
1433
        inputSampleFormat = inputParameters->sampleFormat;
 
1434
 
 
1435
        /* all standard sample formats are supported by the buffer adapter,
 
1436
            this implementation doesn't support any custom sample formats */
 
1437
        if( inputSampleFormat & paCustomFormat )
 
1438
            return paSampleFormatNotSupported;
 
1439
            
 
1440
        /* unless alternate device specification is supported, reject the use of
 
1441
            paUseHostApiSpecificDeviceSpecification */
 
1442
 
 
1443
        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
 
1444
            return paInvalidDevice;
 
1445
 
 
1446
        asioDeviceIndex = inputParameters->device;
 
1447
 
 
1448
        /* validate inputStreamInfo */
 
1449
        /** @todo do more validation here */
 
1450
        // if( inputParameters->hostApiSpecificStreamInfo )
 
1451
        //    return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
 
1452
    }
 
1453
    else
 
1454
    {
 
1455
        inputChannelCount = 0;
 
1456
    }
 
1457
 
 
1458
    if( outputParameters )
 
1459
    {
 
1460
        outputChannelCount = outputParameters->channelCount;
 
1461
        outputSampleFormat = outputParameters->sampleFormat;
 
1462
 
 
1463
        /* all standard sample formats are supported by the buffer adapter,
 
1464
            this implementation doesn't support any custom sample formats */
 
1465
        if( outputSampleFormat & paCustomFormat )
 
1466
            return paSampleFormatNotSupported;
 
1467
            
 
1468
        /* unless alternate device specification is supported, reject the use of
 
1469
            paUseHostApiSpecificDeviceSpecification */
 
1470
 
 
1471
        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
 
1472
            return paInvalidDevice;
 
1473
 
 
1474
        asioDeviceIndex = outputParameters->device;
 
1475
 
 
1476
        /* validate outputStreamInfo */
 
1477
        /** @todo do more validation here */
 
1478
        // if( outputParameters->hostApiSpecificStreamInfo )
 
1479
        //    return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
 
1480
    }
 
1481
    else
 
1482
    {
 
1483
        outputChannelCount = 0;
 
1484
    }
 
1485
 
 
1486
 
 
1487
 
 
1488
    /* if an ASIO device is open we can only get format information for the currently open device */
 
1489
 
 
1490
    if( asioHostApi->openAsioDeviceIndex != paNoDevice 
 
1491
            && asioHostApi->openAsioDeviceIndex != asioDeviceIndex )
 
1492
    {
 
1493
        return paDeviceUnavailable;
 
1494
    }
 
1495
 
 
1496
 
 
1497
    /* NOTE: we load the driver and use its current settings
 
1498
        rather than the ones in our device info structure which may be stale */
 
1499
 
 
1500
    /* open the device if it's not already open */
 
1501
    if( asioHostApi->openAsioDeviceIndex == paNoDevice )
 
1502
    {
 
1503
        result = LoadAsioDriver( asioHostApi, asioHostApi->inheritedHostApiRep.deviceInfos[ asioDeviceIndex ]->name,
 
1504
                driverInfo, asioHostApi->systemSpecific );
 
1505
        if( result != paNoError )
 
1506
            return result;
 
1507
    }
 
1508
 
 
1509
    /* check that input device can support inputChannelCount */
 
1510
    if( inputChannelCount > 0 )
 
1511
    {
 
1512
        if( inputChannelCount > driverInfo->inputChannelCount )
 
1513
        {
 
1514
            result = paInvalidChannelCount;
 
1515
            goto done;
 
1516
        }
 
1517
    }
 
1518
 
 
1519
    /* check that output device can support outputChannelCount */
 
1520
    if( outputChannelCount )
 
1521
    {
 
1522
        if( outputChannelCount > driverInfo->outputChannelCount )
 
1523
        {
 
1524
            result = paInvalidChannelCount;
 
1525
            goto done;
 
1526
        }
 
1527
    }
 
1528
    
 
1529
    /* query for sample rate support */
 
1530
    asioError = ASIOCanSampleRate( sampleRate );
 
1531
    if( asioError == ASE_NoClock || asioError == ASE_NotPresent )
 
1532
    {
 
1533
        result = paInvalidSampleRate;
 
1534
        goto done;
 
1535
    }
 
1536
 
 
1537
done:
 
1538
    /* close the device if it wasn't already open */
 
1539
    if( asioHostApi->openAsioDeviceIndex == paNoDevice )
 
1540
    {
 
1541
        UnloadAsioDriver(); /* not sure if we should check for errors here */
 
1542
    }
 
1543
 
 
1544
    if( result == paNoError )
 
1545
        return paFormatIsSupported;
 
1546
    else
 
1547
        return result;
 
1548
}
 
1549
 
 
1550
 
 
1551
 
 
1552
/** A data structure specifically for storing blocking i/o related data. */
 
1553
typedef struct PaAsioStreamBlockingState
 
1554
{
 
1555
    int stopFlag; /**< Flag indicating that block processing is to be stopped. */
 
1556
 
 
1557
    unsigned long writeBuffersRequested; /**< The number of available output buffers, requested by the #WriteStream() function. */
 
1558
    unsigned long readFramesRequested;   /**< The number of available input frames, requested by the #ReadStream() function. */
 
1559
 
 
1560
    int writeBuffersRequestedFlag; /**< Flag to indicate that #WriteStream() has requested more output buffers to be available. */
 
1561
    int readFramesRequestedFlag;   /**< Flag to indicate that #ReadStream() requires more input frames to be available. */
 
1562
 
 
1563
    HANDLE writeBuffersReadyEvent; /**< Event to signal that requested output buffers are available. */
 
1564
    HANDLE readFramesReadyEvent;   /**< Event to signal that requested input frames are available. */
 
1565
 
 
1566
    void *writeRingBufferData; /**< The actual ring buffer memory, used by the output ring buffer. */
 
1567
    void *readRingBufferData;  /**< The actual ring buffer memory, used by the input ring buffer. */
 
1568
 
 
1569
    PaUtilRingBuffer writeRingBuffer; /**< Frame-aligned blocking i/o ring buffer to store output data (interleaved user format). */
 
1570
    PaUtilRingBuffer readRingBuffer;  /**< Frame-aligned blocking i/o ring buffer to store input data (interleaved user format). */
 
1571
 
 
1572
    long writeRingBufferInitialFrames; /**< The initial number of silent frames within the output ring buffer. */
 
1573
 
 
1574
    const void **writeStreamBuffer; /**< Temp buffer, used by #WriteStream() for handling non-interleaved data. */
 
1575
    void **readStreamBuffer; /**< Temp buffer, used by #ReadStream() for handling non-interleaved data. */
 
1576
 
 
1577
    PaUtilBufferProcessor bufferProcessor; /**< Buffer processor, used to handle the blocking i/o ring buffers. */
 
1578
 
 
1579
    int outputUnderflowFlag; /**< Flag to signal an output underflow from within the callback function. */
 
1580
    int inputOverflowFlag; /**< Flag to signal an input overflow from within the callback function. */
 
1581
}
 
1582
PaAsioStreamBlockingState;
 
1583
 
 
1584
 
 
1585
 
 
1586
/* PaAsioStream - a stream data structure specifically for this implementation */
 
1587
 
 
1588
typedef struct PaAsioStream
 
1589
{
 
1590
    PaUtilStreamRepresentation streamRepresentation;
 
1591
    PaUtilCpuLoadMeasurer cpuLoadMeasurer;
 
1592
    PaUtilBufferProcessor bufferProcessor;
 
1593
 
 
1594
    PaAsioHostApiRepresentation *asioHostApi;
 
1595
    unsigned long framesPerHostCallback;
 
1596
 
 
1597
    /* ASIO driver info  - these may not be needed for the life of the stream,
 
1598
        but store them here until we work out how format conversion is going
 
1599
        to work. */
 
1600
 
 
1601
    ASIOBufferInfo *asioBufferInfos;
 
1602
    ASIOChannelInfo *asioChannelInfos;
 
1603
    long inputLatency, outputLatency; // actual latencies returned by asio
 
1604
 
 
1605
    long inputChannelCount, outputChannelCount;
 
1606
    bool postOutput;
 
1607
 
 
1608
    void **bufferPtrs; /* this is carved up for inputBufferPtrs and outputBufferPtrs */
 
1609
    void **inputBufferPtrs[2];
 
1610
    void **outputBufferPtrs[2];
 
1611
 
 
1612
    PaAsioBufferConverter *inputBufferConverter;
 
1613
    long inputShift;
 
1614
    PaAsioBufferConverter *outputBufferConverter;
 
1615
    long outputShift;
 
1616
 
 
1617
    volatile bool stopProcessing;
 
1618
    int stopPlayoutCount;
 
1619
    HANDLE completedBuffersPlayedEvent;
 
1620
 
 
1621
    bool streamFinishedCallbackCalled;
 
1622
    int isStopped;
 
1623
    volatile int isActive;
 
1624
    volatile bool zeroOutput; /* all future calls to the callback will output silence */
 
1625
 
 
1626
    volatile long reenterCount;
 
1627
    volatile long reenterError;
 
1628
 
 
1629
    PaStreamCallbackFlags callbackFlags;
 
1630
 
 
1631
    PaAsioStreamBlockingState *blockingState; /**< Blocking i/o data struct, or NULL when using callback interface. */
 
1632
}
 
1633
PaAsioStream;
 
1634
 
 
1635
static PaAsioStream *theAsioStream = 0; /* due to ASIO sdk limitations there can be only one stream */
 
1636
 
 
1637
 
 
1638
static void ZeroOutputBuffers( PaAsioStream *stream, long index )
 
1639
{
 
1640
    int i;
 
1641
 
 
1642
    for( i=0; i < stream->outputChannelCount; ++i )
 
1643
    {
 
1644
        void *buffer = stream->asioBufferInfos[ i + stream->inputChannelCount ].buffers[index];
 
1645
 
 
1646
        int bytesPerSample = BytesPerAsioSample( stream->asioChannelInfos[ i + stream->inputChannelCount ].type );
 
1647
 
 
1648
        memset( buffer, 0, stream->framesPerHostCallback * bytesPerSample );
 
1649
    }
 
1650
}
 
1651
 
 
1652
 
 
1653
static unsigned long SelectHostBufferSize( unsigned long suggestedLatencyFrames,
 
1654
        PaAsioDriverInfo *driverInfo )
 
1655
{
 
1656
    unsigned long result;
 
1657
 
 
1658
    if( suggestedLatencyFrames == 0 )
 
1659
    {
 
1660
        result = driverInfo->bufferPreferredSize;
 
1661
    }
 
1662
    else{
 
1663
        if( suggestedLatencyFrames <= (unsigned long)driverInfo->bufferMinSize )
 
1664
        {
 
1665
            result = driverInfo->bufferMinSize;
 
1666
        }
 
1667
        else if( suggestedLatencyFrames >= (unsigned long)driverInfo->bufferMaxSize )
 
1668
        {
 
1669
            result = driverInfo->bufferMaxSize;
 
1670
        }
 
1671
        else
 
1672
        {
 
1673
            if( driverInfo->bufferGranularity == -1 )
 
1674
            {
 
1675
                /* power-of-two */
 
1676
                result = 2;
 
1677
 
 
1678
                while( result < suggestedLatencyFrames )
 
1679
                    result *= 2;
 
1680
 
 
1681
                if( result < (unsigned long)driverInfo->bufferMinSize )
 
1682
                    result = driverInfo->bufferMinSize;
 
1683
 
 
1684
                if( result > (unsigned long)driverInfo->bufferMaxSize )
 
1685
                    result = driverInfo->bufferMaxSize;
 
1686
            }
 
1687
            else if( driverInfo->bufferGranularity == 0 )
 
1688
            {
 
1689
                /* the documentation states that bufferGranularity should be
 
1690
                    zero when bufferMinSize, bufferMaxSize and
 
1691
                    bufferPreferredSize are the same. We assume that is the case.
 
1692
                */
 
1693
 
 
1694
                result = driverInfo->bufferPreferredSize;
 
1695
            }
 
1696
            else
 
1697
            {
 
1698
                /* modulo granularity */
 
1699
 
 
1700
                unsigned long remainder =
 
1701
                        suggestedLatencyFrames % driverInfo->bufferGranularity;
 
1702
 
 
1703
                if( remainder == 0 )
 
1704
                {
 
1705
                    result = suggestedLatencyFrames;
 
1706
                }
 
1707
                else
 
1708
                {
 
1709
                    result = suggestedLatencyFrames
 
1710
                            + (driverInfo->bufferGranularity - remainder);
 
1711
 
 
1712
                    if( result > (unsigned long)driverInfo->bufferMaxSize )
 
1713
                        result = driverInfo->bufferMaxSize;
 
1714
                }
 
1715
            }
 
1716
        }
 
1717
    }
 
1718
 
 
1719
    return result;
 
1720
}
 
1721
 
 
1722
 
 
1723
/* returns channelSelectors if present */
 
1724
 
 
1725
static PaError ValidateAsioSpecificStreamInfo(
 
1726
        const PaStreamParameters *streamParameters,
 
1727
        const PaAsioStreamInfo *streamInfo,
 
1728
        int deviceChannelCount,
 
1729
        int **channelSelectors )
 
1730
{
 
1731
    if( streamInfo )
 
1732
    {
 
1733
        if( streamInfo->size != sizeof( PaAsioStreamInfo )
 
1734
                || streamInfo->version != 1 )
 
1735
        {
 
1736
            return paIncompatibleHostApiSpecificStreamInfo;
 
1737
        }
 
1738
 
 
1739
        if( streamInfo->flags & paAsioUseChannelSelectors )
 
1740
            *channelSelectors = streamInfo->channelSelectors;
 
1741
 
 
1742
        if( !(*channelSelectors) )
 
1743
            return paIncompatibleHostApiSpecificStreamInfo;
 
1744
 
 
1745
        for( int i=0; i < streamParameters->channelCount; ++i ){
 
1746
             if( (*channelSelectors)[i] < 0
 
1747
                    || (*channelSelectors)[i] >= deviceChannelCount ){
 
1748
                return paInvalidChannelCount;
 
1749
             }           
 
1750
        }
 
1751
    }
 
1752
 
 
1753
    return paNoError;
 
1754
}
 
1755
 
 
1756
 
 
1757
static bool IsUsingExternalClockSource()
 
1758
{
 
1759
    bool result = false;
 
1760
    ASIOError asioError;
 
1761
    ASIOClockSource clocks[32];
 
1762
    long numSources=32;
 
1763
 
 
1764
    /* davidv: listing ASIO Clock sources. there is an ongoing investigation by
 
1765
       me about whether or not to call ASIOSetSampleRate if an external Clock is
 
1766
       used. A few drivers expected different things here */
 
1767
    
 
1768
    asioError = ASIOGetClockSources(clocks, &numSources);
 
1769
    if( asioError != ASE_OK ){
 
1770
        PA_DEBUG(("ERROR: ASIOGetClockSources: %s\n", PaAsio_GetAsioErrorText(asioError) ));
 
1771
    }else{
 
1772
        PA_DEBUG(("INFO ASIOGetClockSources listing %d clocks\n", numSources ));
 
1773
        for (int i=0;i<numSources;++i){
 
1774
            PA_DEBUG(("ASIOClockSource%d %s current:%d\n", i, clocks[i].name, clocks[i].isCurrentSource ));
 
1775
           
 
1776
            if (clocks[i].isCurrentSource)
 
1777
                result = true;
 
1778
        }
 
1779
    }
 
1780
 
 
1781
    return result;
 
1782
}
 
1783
 
 
1784
 
 
1785
static PaError ValidateAndSetSampleRate( double sampleRate )
 
1786
{
 
1787
    PaError result = paNoError;
 
1788
    ASIOError asioError;
 
1789
 
 
1790
    // check that the device supports the requested sample rate 
 
1791
 
 
1792
    asioError = ASIOCanSampleRate( sampleRate );
 
1793
    PA_DEBUG(("ASIOCanSampleRate(%f):%d\n", sampleRate, asioError ));
 
1794
 
 
1795
    if( asioError != ASE_OK )
 
1796
    {
 
1797
        result = paInvalidSampleRate;
 
1798
        PA_DEBUG(("ERROR: ASIOCanSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
 
1799
        goto error;
 
1800
    }
 
1801
 
 
1802
    // retrieve the current sample rate, we only change to the requested
 
1803
    // sample rate if the device is not already in that rate.
 
1804
 
 
1805
    ASIOSampleRate oldRate;
 
1806
    asioError = ASIOGetSampleRate(&oldRate);
 
1807
    if( asioError != ASE_OK )
 
1808
    {
 
1809
        result = paInvalidSampleRate;
 
1810
        PA_DEBUG(("ERROR: ASIOGetSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
 
1811
        goto error;
 
1812
    }
 
1813
    PA_DEBUG(("ASIOGetSampleRate:%f\n",oldRate));
 
1814
 
 
1815
    if (oldRate != sampleRate){
 
1816
        /* Set sample rate */
 
1817
 
 
1818
        PA_DEBUG(("before ASIOSetSampleRate(%f)\n",sampleRate));
 
1819
 
 
1820
        /*
 
1821
            If you have problems with some drivers when externally clocked, 
 
1822
            try switching on the following line and commenting out the one after it.
 
1823
            See IsUsingExternalClockSource() for more info.
 
1824
        */
 
1825
        //if( IsUsingExternalClockSource() ){
 
1826
        if( false ){
 
1827
            asioError = ASIOSetSampleRate( 0 );
 
1828
        }else{
 
1829
            asioError = ASIOSetSampleRate( sampleRate );
 
1830
        }
 
1831
        if( asioError != ASE_OK )
 
1832
        {
 
1833
            result = paInvalidSampleRate;
 
1834
            PA_DEBUG(("ERROR: ASIOSetSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
 
1835
            goto error;
 
1836
        }
 
1837
        PA_DEBUG(("after ASIOSetSampleRate(%f)\n",sampleRate));
 
1838
    }
 
1839
    else
 
1840
    {
 
1841
        PA_DEBUG(("No Need to change SR\n"));
 
1842
    }
 
1843
 
 
1844
error:
 
1845
    return result;
 
1846
}
 
1847
 
 
1848
 
 
1849
/* see pa_hostapi.h for a list of validity guarantees made about OpenStream  parameters */
 
1850
 
 
1851
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
 
1852
                           PaStream** s,
 
1853
                           const PaStreamParameters *inputParameters,
 
1854
                           const PaStreamParameters *outputParameters,
 
1855
                           double sampleRate,
 
1856
                           unsigned long framesPerBuffer,
 
1857
                           PaStreamFlags streamFlags,
 
1858
                           PaStreamCallback *streamCallback,
 
1859
                           void *userData )
 
1860
{
 
1861
    PaError result = paNoError;
 
1862
    PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
 
1863
    PaAsioStream *stream = 0;
 
1864
    PaAsioStreamInfo *inputStreamInfo, *outputStreamInfo;
 
1865
    unsigned long framesPerHostBuffer;
 
1866
    int inputChannelCount, outputChannelCount;
 
1867
    PaSampleFormat inputSampleFormat, outputSampleFormat;
 
1868
    PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
 
1869
    unsigned long suggestedInputLatencyFrames;
 
1870
    unsigned long suggestedOutputLatencyFrames;
 
1871
    PaDeviceIndex asioDeviceIndex;
 
1872
    ASIOError asioError;
 
1873
    int asioIsInitialized = 0;
 
1874
    int asioBuffersCreated = 0;
 
1875
    int completedBuffersPlayedEventInited = 0;
 
1876
    int i;
 
1877
    PaAsioDriverInfo *driverInfo;
 
1878
    int *inputChannelSelectors = 0;
 
1879
    int *outputChannelSelectors = 0;
 
1880
 
 
1881
    /* Are we using blocking i/o interface? */
 
1882
    int usingBlockingIo = ( !streamCallback ) ? TRUE : FALSE;
 
1883
    /* Blocking i/o stuff */
 
1884
    long lBlockingBufferSize     = 0; /* Desired ring buffer size in samples. */
 
1885
    long lBlockingBufferSizePow2 = 0; /* Power-of-2 rounded ring buffer size. */
 
1886
    long lBytesPerFrame          = 0; /* Number of bytes per input/output frame. */
 
1887
    int blockingWriteBuffersReadyEventInitialized = 0; /* Event init flag. */
 
1888
    int blockingReadFramesReadyEventInitialized   = 0; /* Event init flag. */
 
1889
 
 
1890
    int callbackBufferProcessorInited = FALSE;
 
1891
    int blockingBufferProcessorInited = FALSE;
 
1892
 
 
1893
    /* unless we move to using lower level ASIO calls, we can only have
 
1894
        one device open at a time */
 
1895
    if( asioHostApi->openAsioDeviceIndex != paNoDevice )
 
1896
    {
 
1897
        PA_DEBUG(("OpenStream paDeviceUnavailable\n"));
 
1898
        return paDeviceUnavailable;
 
1899
    }
 
1900
 
 
1901
    assert( theAsioStream == 0 );
 
1902
 
 
1903
    if( inputParameters && outputParameters )
 
1904
    {
 
1905
        /* full duplex ASIO stream must use the same device for input and output */
 
1906
 
 
1907
        if( inputParameters->device != outputParameters->device )
 
1908
        {
 
1909
            PA_DEBUG(("OpenStream paBadIODeviceCombination\n"));
 
1910
            return paBadIODeviceCombination;
 
1911
        }
 
1912
    }
 
1913
 
 
1914
    if( inputParameters )
 
1915
    {
 
1916
        inputChannelCount = inputParameters->channelCount;
 
1917
        inputSampleFormat = inputParameters->sampleFormat;
 
1918
        suggestedInputLatencyFrames = (unsigned long)((inputParameters->suggestedLatency * sampleRate)+0.5f);
 
1919
 
 
1920
        /* unless alternate device specification is supported, reject the use of
 
1921
            paUseHostApiSpecificDeviceSpecification */
 
1922
        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
 
1923
            return paInvalidDevice;
 
1924
 
 
1925
        asioDeviceIndex = inputParameters->device;
 
1926
 
 
1927
        PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[asioDeviceIndex];
 
1928
 
 
1929
        /* validate hostApiSpecificStreamInfo */
 
1930
        inputStreamInfo = (PaAsioStreamInfo*)inputParameters->hostApiSpecificStreamInfo;
 
1931
        result = ValidateAsioSpecificStreamInfo( inputParameters, inputStreamInfo,
 
1932
            asioDeviceInfo->commonDeviceInfo.maxInputChannels,
 
1933
            &inputChannelSelectors
 
1934
        );
 
1935
        if( result != paNoError ) return result;
 
1936
    }
 
1937
    else
 
1938
    {
 
1939
        inputChannelCount = 0;
 
1940
        inputSampleFormat = 0;
 
1941
        suggestedInputLatencyFrames = 0;
 
1942
    }
 
1943
 
 
1944
    if( outputParameters )
 
1945
    {
 
1946
        outputChannelCount = outputParameters->channelCount;
 
1947
        outputSampleFormat = outputParameters->sampleFormat;
 
1948
        suggestedOutputLatencyFrames = (unsigned long)((outputParameters->suggestedLatency * sampleRate)+0.5f);
 
1949
 
 
1950
        /* unless alternate device specification is supported, reject the use of
 
1951
            paUseHostApiSpecificDeviceSpecification */
 
1952
        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
 
1953
            return paInvalidDevice;
 
1954
 
 
1955
        asioDeviceIndex = outputParameters->device;
 
1956
 
 
1957
        PaAsioDeviceInfo *asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[asioDeviceIndex];
 
1958
 
 
1959
        /* validate hostApiSpecificStreamInfo */
 
1960
        outputStreamInfo = (PaAsioStreamInfo*)outputParameters->hostApiSpecificStreamInfo;
 
1961
        result = ValidateAsioSpecificStreamInfo( outputParameters, outputStreamInfo,
 
1962
            asioDeviceInfo->commonDeviceInfo.maxOutputChannels,
 
1963
            &outputChannelSelectors
 
1964
        );
 
1965
        if( result != paNoError ) return result;
 
1966
    }
 
1967
    else
 
1968
    {
 
1969
        outputChannelCount = 0;
 
1970
        outputSampleFormat = 0;
 
1971
        suggestedOutputLatencyFrames = 0;
 
1972
    }
 
1973
 
 
1974
    driverInfo = &asioHostApi->openAsioDriverInfo;
 
1975
 
 
1976
    /* NOTE: we load the driver and use its current settings
 
1977
        rather than the ones in our device info structure which may be stale */
 
1978
 
 
1979
    result = LoadAsioDriver( asioHostApi, asioHostApi->inheritedHostApiRep.deviceInfos[ asioDeviceIndex ]->name,
 
1980
            driverInfo, asioHostApi->systemSpecific );
 
1981
    if( result == paNoError )
 
1982
        asioIsInitialized = 1;
 
1983
    else{
 
1984
        PA_DEBUG(("OpenStream ERROR1 - LoadAsioDriver returned %d\n", result));
 
1985
        goto error;
 
1986
    }
 
1987
 
 
1988
    /* check that input device can support inputChannelCount */
 
1989
    if( inputChannelCount > 0 )
 
1990
    {
 
1991
        if( inputChannelCount > driverInfo->inputChannelCount )
 
1992
        {
 
1993
            result = paInvalidChannelCount;
 
1994
            PA_DEBUG(("OpenStream ERROR2\n"));
 
1995
            goto error;
 
1996
        }
 
1997
    }
 
1998
 
 
1999
    /* check that output device can support outputChannelCount */
 
2000
    if( outputChannelCount )
 
2001
    {
 
2002
        if( outputChannelCount > driverInfo->outputChannelCount )
 
2003
        {
 
2004
            result = paInvalidChannelCount;
 
2005
            PA_DEBUG(("OpenStream ERROR3\n"));
 
2006
            goto error;
 
2007
        }
 
2008
    }
 
2009
 
 
2010
    result = ValidateAndSetSampleRate( sampleRate );
 
2011
    if( result != paNoError )
 
2012
        goto error;
 
2013
 
 
2014
    /*
 
2015
        IMPLEMENT ME:
 
2016
            - if a full duplex stream is requested, check that the combination
 
2017
                of input and output parameters is supported
 
2018
    */
 
2019
 
 
2020
    /* validate platform specific flags */
 
2021
    if( (streamFlags & paPlatformSpecificFlags) != 0 ){
 
2022
        PA_DEBUG(("OpenStream invalid flags!!\n"));
 
2023
        return paInvalidFlag; /* unexpected platform specific flag */
 
2024
    }
 
2025
 
 
2026
 
 
2027
    stream = (PaAsioStream*)PaUtil_AllocateMemory( sizeof(PaAsioStream) );
 
2028
    if( !stream )
 
2029
    {
 
2030
        result = paInsufficientMemory;
 
2031
        PA_DEBUG(("OpenStream ERROR5\n"));
 
2032
        goto error;
 
2033
    }
 
2034
    stream->blockingState = NULL; /* Blocking i/o not initialized, yet. */
 
2035
 
 
2036
 
 
2037
    stream->completedBuffersPlayedEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
 
2038
    if( stream->completedBuffersPlayedEvent == NULL )
 
2039
    {
 
2040
        result = paUnanticipatedHostError;
 
2041
        PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
 
2042
        PA_DEBUG(("OpenStream ERROR6\n"));
 
2043
        goto error;
 
2044
    }
 
2045
    completedBuffersPlayedEventInited = 1;
 
2046
 
 
2047
 
 
2048
    stream->asioBufferInfos = 0; /* for deallocation in error */
 
2049
    stream->asioChannelInfos = 0; /* for deallocation in error */
 
2050
    stream->bufferPtrs = 0; /* for deallocation in error */
 
2051
 
 
2052
    /* Using blocking i/o interface... */
 
2053
    if( usingBlockingIo )
 
2054
    {
 
2055
        /* Blocking i/o is implemented by running callback mode, using a special blocking i/o callback. */
 
2056
        streamCallback = BlockingIoPaCallback; /* Setup PA to use the ASIO blocking i/o callback. */
 
2057
        userData       = &theAsioStream;       /* The callback user data will be the PA ASIO stream. */
 
2058
        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
 
2059
                                               &asioHostApi->blockingStreamInterface, streamCallback, userData );
 
2060
    }
 
2061
    else /* Using callback interface... */
 
2062
    {
 
2063
        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
 
2064
                                               &asioHostApi->callbackStreamInterface, streamCallback, userData );
 
2065
    }
 
2066
 
 
2067
 
 
2068
    PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
 
2069
 
 
2070
 
 
2071
    stream->asioBufferInfos = (ASIOBufferInfo*)PaUtil_AllocateMemory(
 
2072
            sizeof(ASIOBufferInfo) * (inputChannelCount + outputChannelCount) );
 
2073
    if( !stream->asioBufferInfos )
 
2074
    {
 
2075
        result = paInsufficientMemory;
 
2076
        PA_DEBUG(("OpenStream ERROR7\n"));
 
2077
        goto error;
 
2078
    }
 
2079
 
 
2080
 
 
2081
    for( i=0; i < inputChannelCount; ++i )
 
2082
    {
 
2083
        ASIOBufferInfo *info = &stream->asioBufferInfos[i];
 
2084
 
 
2085
        info->isInput = ASIOTrue;
 
2086
 
 
2087
        if( inputChannelSelectors ){
 
2088
            // inputChannelSelectors values have already been validated in
 
2089
            // ValidateAsioSpecificStreamInfo() above
 
2090
            info->channelNum = inputChannelSelectors[i];
 
2091
        }else{
 
2092
            info->channelNum = i;
 
2093
        }
 
2094
 
 
2095
        info->buffers[0] = info->buffers[1] = 0;
 
2096
    }
 
2097
 
 
2098
    for( i=0; i < outputChannelCount; ++i ){
 
2099
        ASIOBufferInfo *info = &stream->asioBufferInfos[inputChannelCount+i];
 
2100
 
 
2101
        info->isInput = ASIOFalse;
 
2102
 
 
2103
        if( outputChannelSelectors ){
 
2104
            // outputChannelSelectors values have already been validated in
 
2105
            // ValidateAsioSpecificStreamInfo() above
 
2106
            info->channelNum = outputChannelSelectors[i];
 
2107
        }else{
 
2108
            info->channelNum = i;
 
2109
        }
 
2110
        
 
2111
        info->buffers[0] = info->buffers[1] = 0;
 
2112
    }
 
2113
 
 
2114
 
 
2115
    /* Using blocking i/o interface... */
 
2116
    if( usingBlockingIo )
 
2117
    {
 
2118
/** @todo REVIEW selection of host buffer size for blocking i/o */
 
2119
        /* Use default host latency for blocking i/o. */
 
2120
        framesPerHostBuffer = SelectHostBufferSize( 0, driverInfo );
 
2121
 
 
2122
    }
 
2123
    else /* Using callback interface... */
 
2124
    {
 
2125
        framesPerHostBuffer = SelectHostBufferSize(
 
2126
                (( suggestedInputLatencyFrames > suggestedOutputLatencyFrames )
 
2127
                        ? suggestedInputLatencyFrames : suggestedOutputLatencyFrames),
 
2128
                driverInfo );
 
2129
    }
 
2130
 
 
2131
 
 
2132
    PA_DEBUG(("PaAsioOpenStream: framesPerHostBuffer :%d\n",  framesPerHostBuffer));
 
2133
 
 
2134
    asioError = ASIOCreateBuffers( stream->asioBufferInfos,
 
2135
            inputChannelCount+outputChannelCount,
 
2136
            framesPerHostBuffer, &asioCallbacks_ );
 
2137
 
 
2138
    if( asioError != ASE_OK
 
2139
            && framesPerHostBuffer != (unsigned long)driverInfo->bufferPreferredSize )
 
2140
    {
 
2141
        PA_DEBUG(("ERROR: ASIOCreateBuffers: %s\n", PaAsio_GetAsioErrorText(asioError) ));
 
2142
        /*
 
2143
            Some buggy drivers (like the Hoontech DSP24) give incorrect
 
2144
            [min, preferred, max] values They should work with the preferred size
 
2145
            value, thus if Pa_ASIO_CreateBuffers fails with the hostBufferSize
 
2146
            computed in SelectHostBufferSize, we try again with the preferred size.
 
2147
        */
 
2148
 
 
2149
        framesPerHostBuffer = driverInfo->bufferPreferredSize;
 
2150
 
 
2151
        PA_DEBUG(("PaAsioOpenStream: CORRECTED framesPerHostBuffer :%d\n",  framesPerHostBuffer));
 
2152
 
 
2153
        ASIOError asioError2 = ASIOCreateBuffers( stream->asioBufferInfos,
 
2154
                inputChannelCount+outputChannelCount,
 
2155
                 framesPerHostBuffer, &asioCallbacks_ );
 
2156
        if( asioError2 == ASE_OK )
 
2157
            asioError = ASE_OK;
 
2158
    }
 
2159
 
 
2160
    if( asioError != ASE_OK )
 
2161
    {
 
2162
        result = paUnanticipatedHostError;
 
2163
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
 
2164
        PA_DEBUG(("OpenStream ERROR9\n"));
 
2165
        goto error;
 
2166
    }
 
2167
 
 
2168
    asioBuffersCreated = 1;
 
2169
 
 
2170
    stream->asioChannelInfos = (ASIOChannelInfo*)PaUtil_AllocateMemory(
 
2171
            sizeof(ASIOChannelInfo) * (inputChannelCount + outputChannelCount) );
 
2172
    if( !stream->asioChannelInfos )
 
2173
    {
 
2174
        result = paInsufficientMemory;
 
2175
        PA_DEBUG(("OpenStream ERROR10\n"));
 
2176
        goto error;
 
2177
    }
 
2178
 
 
2179
    for( i=0; i < inputChannelCount + outputChannelCount; ++i )
 
2180
    {
 
2181
        stream->asioChannelInfos[i].channel = stream->asioBufferInfos[i].channelNum;
 
2182
        stream->asioChannelInfos[i].isInput = stream->asioBufferInfos[i].isInput;
 
2183
        asioError = ASIOGetChannelInfo( &stream->asioChannelInfos[i] );
 
2184
        if( asioError != ASE_OK )
 
2185
        {
 
2186
            result = paUnanticipatedHostError;
 
2187
            PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
 
2188
            PA_DEBUG(("OpenStream ERROR11\n"));
 
2189
            goto error;
 
2190
        }
 
2191
    }
 
2192
 
 
2193
    stream->bufferPtrs = (void**)PaUtil_AllocateMemory(
 
2194
            2 * sizeof(void*) * (inputChannelCount + outputChannelCount) );
 
2195
    if( !stream->bufferPtrs )
 
2196
    {
 
2197
        result = paInsufficientMemory;
 
2198
        PA_DEBUG(("OpenStream ERROR12\n"));
 
2199
        goto error;
 
2200
    }
 
2201
 
 
2202
    if( inputChannelCount > 0 )
 
2203
    {
 
2204
        stream->inputBufferPtrs[0] = stream-> bufferPtrs;
 
2205
        stream->inputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount];
 
2206
 
 
2207
        for( i=0; i<inputChannelCount; ++i )
 
2208
        {
 
2209
            stream->inputBufferPtrs[0][i] = stream->asioBufferInfos[i].buffers[0];
 
2210
            stream->inputBufferPtrs[1][i] = stream->asioBufferInfos[i].buffers[1];
 
2211
        }
 
2212
    }
 
2213
    else
 
2214
    {
 
2215
        stream->inputBufferPtrs[0] = 0;
 
2216
        stream->inputBufferPtrs[1] = 0;
 
2217
    }
 
2218
 
 
2219
    if( outputChannelCount > 0 )
 
2220
    {
 
2221
        stream->outputBufferPtrs[0] = &stream->bufferPtrs[inputChannelCount*2];
 
2222
        stream->outputBufferPtrs[1] = &stream->bufferPtrs[inputChannelCount*2 + outputChannelCount];
 
2223
 
 
2224
        for( i=0; i<outputChannelCount; ++i )
 
2225
        {
 
2226
            stream->outputBufferPtrs[0][i] = stream->asioBufferInfos[inputChannelCount+i].buffers[0];
 
2227
            stream->outputBufferPtrs[1][i] = stream->asioBufferInfos[inputChannelCount+i].buffers[1];
 
2228
        }
 
2229
    }
 
2230
    else
 
2231
    {
 
2232
        stream->outputBufferPtrs[0] = 0;
 
2233
        stream->outputBufferPtrs[1] = 0;
 
2234
    }
 
2235
 
 
2236
    if( inputChannelCount > 0 )
 
2237
    {
 
2238
        /* FIXME: assume all channels use the same type for now */
 
2239
        ASIOSampleType inputType = stream->asioChannelInfos[0].type;
 
2240
 
 
2241
        PA_DEBUG(("ASIO Input  type:%d",inputType));
 
2242
        AsioSampleTypeLOG(inputType);
 
2243
        hostInputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( inputType );
 
2244
 
 
2245
        SelectAsioToPaConverter( inputType, &stream->inputBufferConverter, &stream->inputShift );
 
2246
    }
 
2247
    else
 
2248
    {
 
2249
        hostInputSampleFormat = 0;
 
2250
        stream->inputBufferConverter = 0;
 
2251
    }
 
2252
 
 
2253
    if( outputChannelCount > 0 )
 
2254
    {
 
2255
        /* FIXME: assume all channels use the same type for now */
 
2256
        ASIOSampleType outputType = stream->asioChannelInfos[inputChannelCount].type;
 
2257
 
 
2258
        PA_DEBUG(("ASIO Output type:%d",outputType));
 
2259
        AsioSampleTypeLOG(outputType);
 
2260
        hostOutputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( outputType );
 
2261
 
 
2262
        SelectPaToAsioConverter( outputType, &stream->outputBufferConverter, &stream->outputShift );
 
2263
    }
 
2264
    else
 
2265
    {
 
2266
        hostOutputSampleFormat = 0;
 
2267
        stream->outputBufferConverter = 0;
 
2268
    }
 
2269
 
 
2270
 
 
2271
    ASIOGetLatencies( &stream->inputLatency, &stream->outputLatency );
 
2272
 
 
2273
 
 
2274
    /* Using blocking i/o interface... */
 
2275
    if( usingBlockingIo )
 
2276
    {
 
2277
        /* Allocate the blocking i/o input ring buffer memory. */
 
2278
        stream->blockingState = (PaAsioStreamBlockingState*)PaUtil_AllocateMemory( sizeof(PaAsioStreamBlockingState) );
 
2279
        if( !stream->blockingState )
 
2280
        {
 
2281
            result = paInsufficientMemory;
 
2282
            PA_DEBUG(("ERROR! Blocking i/o interface struct allocation failed in OpenStream()\n"));
 
2283
            goto error;
 
2284
        }
 
2285
 
 
2286
        /* Initialize blocking i/o interface struct. */
 
2287
        stream->blockingState->readFramesReadyEvent   = NULL; /* Uninitialized, yet. */
 
2288
        stream->blockingState->writeBuffersReadyEvent = NULL; /* Uninitialized, yet. */
 
2289
        stream->blockingState->readRingBufferData     = NULL; /* Uninitialized, yet. */
 
2290
        stream->blockingState->writeRingBufferData    = NULL; /* Uninitialized, yet. */
 
2291
        stream->blockingState->readStreamBuffer       = NULL; /* Uninitialized, yet. */
 
2292
        stream->blockingState->writeStreamBuffer      = NULL; /* Uninitialized, yet. */
 
2293
        stream->blockingState->stopFlag               = TRUE; /* Not started, yet. */
 
2294
 
 
2295
 
 
2296
        /* If the user buffer is unspecified */
 
2297
        if( framesPerBuffer == paFramesPerBufferUnspecified )
 
2298
        {
 
2299
            /* Make the user buffer the same size as the host buffer. */
 
2300
            framesPerBuffer = framesPerHostBuffer;
 
2301
        }
 
2302
 
 
2303
 
 
2304
        /* Initialize callback buffer processor. */
 
2305
        result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor               ,
 
2306
                                                    inputChannelCount                     ,
 
2307
                                                    inputSampleFormat & ~paNonInterleaved , /* Ring buffer. */
 
2308
                                                    hostInputSampleFormat                 , /* Host format. */
 
2309
                                                    outputChannelCount                    ,
 
2310
                                                    outputSampleFormat & ~paNonInterleaved, /* Ring buffer. */
 
2311
                                                    hostOutputSampleFormat                , /* Host format. */
 
2312
                                                    sampleRate                            ,
 
2313
                                                    streamFlags                           ,
 
2314
                                                    framesPerBuffer                       , /* Frames per ring buffer block. */
 
2315
                                                    framesPerHostBuffer                   , /* Frames per asio buffer. */
 
2316
                                                    paUtilFixedHostBufferSize             ,
 
2317
                                                    streamCallback                        ,
 
2318
                                                    userData                               );
 
2319
        if( result != paNoError ){
 
2320
            PA_DEBUG(("OpenStream ERROR13\n"));
 
2321
            goto error;
 
2322
        }
 
2323
        callbackBufferProcessorInited = TRUE;
 
2324
 
 
2325
        /* Initialize the blocking i/o buffer processor. */
 
2326
        result = PaUtil_InitializeBufferProcessor(&stream->blockingState->bufferProcessor,
 
2327
                                                   inputChannelCount                     ,
 
2328
                                                   inputSampleFormat                     , /* User format. */
 
2329
                                                   inputSampleFormat & ~paNonInterleaved , /* Ring buffer. */
 
2330
                                                   outputChannelCount                    ,
 
2331
                                                   outputSampleFormat                    , /* User format. */
 
2332
                                                   outputSampleFormat & ~paNonInterleaved, /* Ring buffer. */
 
2333
                                                   sampleRate                            ,
 
2334
                                                   paClipOff | paDitherOff               , /* Don't use dither nor clipping. */
 
2335
                                                   framesPerBuffer                       , /* Frames per user buffer. */
 
2336
                                                   framesPerBuffer                       , /* Frames per ring buffer block. */
 
2337
                                                   paUtilBoundedHostBufferSize           ,
 
2338
                                                   NULL, NULL                            );/* No callback! */
 
2339
        if( result != paNoError ){
 
2340
            PA_DEBUG(("ERROR! Blocking i/o buffer processor initialization failed in OpenStream()\n"));
 
2341
            goto error;
 
2342
        }
 
2343
        blockingBufferProcessorInited = TRUE;
 
2344
 
 
2345
        /* If input is requested. */
 
2346
        if( inputChannelCount )
 
2347
        {
 
2348
            /* Create the callback sync-event. */
 
2349
            stream->blockingState->readFramesReadyEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
 
2350
            if( stream->blockingState->readFramesReadyEvent == NULL )
 
2351
            {
 
2352
                result = paUnanticipatedHostError;
 
2353
                PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
 
2354
                PA_DEBUG(("ERROR! Blocking i/o \"read frames ready\" event creation failed in OpenStream()\n"));
 
2355
                goto error;
 
2356
            }
 
2357
            blockingReadFramesReadyEventInitialized = 1;
 
2358
 
 
2359
 
 
2360
            /* Create pointer buffer to access non-interleaved data in ReadStream() */
 
2361
            stream->blockingState->readStreamBuffer = (void**)PaUtil_AllocateMemory( sizeof(void*) * inputChannelCount );
 
2362
            if( !stream->blockingState->readStreamBuffer )
 
2363
            {
 
2364
                result = paInsufficientMemory;
 
2365
                PA_DEBUG(("ERROR! Blocking i/o read stream buffer allocation failed in OpenStream()\n"));
 
2366
                goto error;
 
2367
            }
 
2368
 
 
2369
            /* The ring buffer should store as many data blocks as needed
 
2370
               to achieve the requested latency. Whereas it must be large
 
2371
               enough to store at least two complete data blocks.
 
2372
 
 
2373
               1) Determine the amount of latency to be added to the
 
2374
                  prefered ASIO latency.
 
2375
               2) Make sure we have at lest one additional latency frame.
 
2376
               3) Divide the number of frames by the desired block size to
 
2377
                  get the number (rounded up to pure integer) of blocks to
 
2378
                  be stored in the buffer.
 
2379
               4) Add one additional block for block processing and convert
 
2380
                  to samples frames.
 
2381
               5) Get the next larger (or equal) power-of-two buffer size.
 
2382
             */
 
2383
            lBlockingBufferSize = suggestedInputLatencyFrames - stream->inputLatency;
 
2384
            lBlockingBufferSize = (lBlockingBufferSize > 0) ? lBlockingBufferSize : 1;
 
2385
            lBlockingBufferSize = (lBlockingBufferSize + framesPerBuffer - 1) / framesPerBuffer;
 
2386
            lBlockingBufferSize = (lBlockingBufferSize + 1) * framesPerBuffer;
 
2387
 
 
2388
            /* Get the next larger or equal power-of-two buffersize. */
 
2389
            lBlockingBufferSizePow2 = 1;
 
2390
            while( lBlockingBufferSize > (lBlockingBufferSizePow2<<=1) );
 
2391
            lBlockingBufferSize = lBlockingBufferSizePow2;
 
2392
 
 
2393
            /* Compute total intput latency in seconds */
 
2394
            stream->streamRepresentation.streamInfo.inputLatency =
 
2395
                (double)( PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor               )
 
2396
                        + PaUtil_GetBufferProcessorInputLatency(&stream->blockingState->bufferProcessor)
 
2397
                        + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer
 
2398
                        + stream->inputLatency )
 
2399
                / sampleRate;
 
2400
 
 
2401
            /* The code below prints the ASIO latency which doesn't include
 
2402
               the buffer processor latency nor the blocking i/o latency. It
 
2403
               reports the added latency separately.
 
2404
            */
 
2405
            PA_DEBUG(("PaAsio : ASIO InputLatency = %ld (%ld ms),\n         added buffProc:%ld (%ld ms),\n         added blocking:%ld (%ld ms)\n",
 
2406
                stream->inputLatency,
 
2407
                (long)( stream->inputLatency * (1000.0 / sampleRate) ),
 
2408
                PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor),
 
2409
                (long)( PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor) * (1000.0 / sampleRate) ),
 
2410
                PaUtil_GetBufferProcessorInputLatency(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer,
 
2411
                (long)( (PaUtil_GetBufferProcessorInputLatency(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer) * (1000.0 / sampleRate) )
 
2412
                ));
 
2413
 
 
2414
            /* Determine the size of ring buffer in bytes. */
 
2415
            lBytesPerFrame = inputChannelCount * Pa_GetSampleSize(inputSampleFormat );
 
2416
 
 
2417
            /* Allocate the blocking i/o input ring buffer memory. */
 
2418
            stream->blockingState->readRingBufferData = (void*)PaUtil_AllocateMemory( lBlockingBufferSize * lBytesPerFrame );
 
2419
            if( !stream->blockingState->readRingBufferData )
 
2420
            {
 
2421
                result = paInsufficientMemory;
 
2422
                PA_DEBUG(("ERROR! Blocking i/o input ring buffer allocation failed in OpenStream()\n"));
 
2423
                goto error;
 
2424
            }
 
2425
 
 
2426
            /* Initialize the input ring buffer struct. */
 
2427
            PaUtil_InitializeRingBuffer( &stream->blockingState->readRingBuffer    ,
 
2428
                                          lBytesPerFrame                           ,
 
2429
                                          lBlockingBufferSize                      ,
 
2430
                                          stream->blockingState->readRingBufferData );
 
2431
        }
 
2432
 
 
2433
        /* If output is requested. */
 
2434
        if( outputChannelCount )
 
2435
        {
 
2436
            stream->blockingState->writeBuffersReadyEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
 
2437
            if( stream->blockingState->writeBuffersReadyEvent == NULL )
 
2438
            {
 
2439
                result = paUnanticipatedHostError;
 
2440
                PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
 
2441
                PA_DEBUG(("ERROR! Blocking i/o \"write buffers ready\" event creation failed in OpenStream()\n"));
 
2442
                goto error;
 
2443
            }
 
2444
            blockingWriteBuffersReadyEventInitialized = 1;
 
2445
 
 
2446
            /* Create pointer buffer to access non-interleaved data in WriteStream() */
 
2447
            stream->blockingState->writeStreamBuffer = (const void**)PaUtil_AllocateMemory( sizeof(const void*) * outputChannelCount );
 
2448
            if( !stream->blockingState->writeStreamBuffer )
 
2449
            {
 
2450
                result = paInsufficientMemory;
 
2451
                PA_DEBUG(("ERROR! Blocking i/o write stream buffer allocation failed in OpenStream()\n"));
 
2452
                goto error;
 
2453
            }
 
2454
 
 
2455
            /* The ring buffer should store as many data blocks as needed
 
2456
               to achieve the requested latency. Whereas it must be large
 
2457
               enough to store at least two complete data blocks.
 
2458
 
 
2459
               1) Determine the amount of latency to be added to the
 
2460
                  prefered ASIO latency.
 
2461
               2) Make sure we have at lest one additional latency frame.
 
2462
               3) Divide the number of frames by the desired block size to
 
2463
                  get the number (rounded up to pure integer) of blocks to
 
2464
                  be stored in the buffer.
 
2465
               4) Add one additional block for block processing and convert
 
2466
                  to samples frames.
 
2467
               5) Get the next larger (or equal) power-of-two buffer size.
 
2468
             */
 
2469
            lBlockingBufferSize = suggestedOutputLatencyFrames - stream->outputLatency;
 
2470
            lBlockingBufferSize = (lBlockingBufferSize > 0) ? lBlockingBufferSize : 1;
 
2471
            lBlockingBufferSize = (lBlockingBufferSize + framesPerBuffer - 1) / framesPerBuffer;
 
2472
            lBlockingBufferSize = (lBlockingBufferSize + 1) * framesPerBuffer;
 
2473
 
 
2474
            /* The buffer size (without the additional block) corresponds
 
2475
               to the initial number of silent samples in the output ring
 
2476
               buffer. */
 
2477
            stream->blockingState->writeRingBufferInitialFrames = lBlockingBufferSize - framesPerBuffer;
 
2478
 
 
2479
            /* Get the next larger or equal power-of-two buffersize. */
 
2480
            lBlockingBufferSizePow2 = 1;
 
2481
            while( lBlockingBufferSize > (lBlockingBufferSizePow2<<=1) );
 
2482
            lBlockingBufferSize = lBlockingBufferSizePow2;
 
2483
 
 
2484
            /* Compute total output latency in seconds */
 
2485
            stream->streamRepresentation.streamInfo.outputLatency =
 
2486
                (double)( PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor               )
 
2487
                        + PaUtil_GetBufferProcessorOutputLatency(&stream->blockingState->bufferProcessor)
 
2488
                        + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer
 
2489
                        + stream->outputLatency )
 
2490
                / sampleRate;
 
2491
 
 
2492
            /* The code below prints the ASIO latency which doesn't include
 
2493
               the buffer processor latency nor the blocking i/o latency. It
 
2494
               reports the added latency separately.
 
2495
            */
 
2496
            PA_DEBUG(("PaAsio : ASIO OutputLatency = %ld (%ld ms),\n         added buffProc:%ld (%ld ms),\n         added blocking:%ld (%ld ms)\n",
 
2497
                stream->outputLatency,
 
2498
                (long)( stream->inputLatency * (1000.0 / sampleRate) ),
 
2499
                PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor),
 
2500
                (long)( PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor) * (1000.0 / sampleRate) ),
 
2501
                PaUtil_GetBufferProcessorOutputLatency(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer,
 
2502
                (long)( (PaUtil_GetBufferProcessorOutputLatency(&stream->blockingState->bufferProcessor) + (lBlockingBufferSize / framesPerBuffer - 1) * framesPerBuffer) * (1000.0 / sampleRate) )
 
2503
                ));
 
2504
 
 
2505
            /* Determine the size of ring buffer in bytes. */
 
2506
            lBytesPerFrame = outputChannelCount * Pa_GetSampleSize(outputSampleFormat);
 
2507
 
 
2508
            /* Allocate the blocking i/o output ring buffer memory. */
 
2509
            stream->blockingState->writeRingBufferData = (void*)PaUtil_AllocateMemory( lBlockingBufferSize * lBytesPerFrame );
 
2510
            if( !stream->blockingState->writeRingBufferData )
 
2511
            {
 
2512
                result = paInsufficientMemory;
 
2513
                PA_DEBUG(("ERROR! Blocking i/o output ring buffer allocation failed in OpenStream()\n"));
 
2514
                goto error;
 
2515
            }
 
2516
 
 
2517
            /* Initialize the output ring buffer struct. */
 
2518
            PaUtil_InitializeRingBuffer( &stream->blockingState->writeRingBuffer    ,
 
2519
                                          lBytesPerFrame                            ,
 
2520
                                          lBlockingBufferSize                       ,
 
2521
                                          stream->blockingState->writeRingBufferData );
 
2522
        }
 
2523
 
 
2524
        stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
 
2525
 
 
2526
 
 
2527
    }
 
2528
    else /* Using callback interface... */
 
2529
    {
 
2530
        result =  PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
 
2531
                        inputChannelCount, inputSampleFormat, hostInputSampleFormat,
 
2532
                        outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
 
2533
                        sampleRate, streamFlags, framesPerBuffer,
 
2534
                        framesPerHostBuffer, paUtilFixedHostBufferSize,
 
2535
                        streamCallback, userData );
 
2536
        if( result != paNoError ){
 
2537
            PA_DEBUG(("OpenStream ERROR13\n"));
 
2538
            goto error;
 
2539
        }
 
2540
        callbackBufferProcessorInited = TRUE;
 
2541
 
 
2542
        stream->streamRepresentation.streamInfo.inputLatency =
 
2543
                (double)( PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)
 
2544
                    + stream->inputLatency) / sampleRate;   // seconds
 
2545
        stream->streamRepresentation.streamInfo.outputLatency =
 
2546
                (double)( PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)
 
2547
                    + stream->outputLatency) / sampleRate; // seconds
 
2548
        stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
 
2549
 
 
2550
        // the code below prints the ASIO latency which doesn't include the
 
2551
        // buffer processor latency. it reports the added latency separately
 
2552
        PA_DEBUG(("PaAsio : ASIO InputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n",
 
2553
                stream->inputLatency,
 
2554
                (long)((stream->inputLatency*1000)/ sampleRate),  
 
2555
                PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor),
 
2556
                (long)((PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)*1000)/ sampleRate)
 
2557
                ));
 
2558
 
 
2559
        PA_DEBUG(("PaAsio : ASIO OuputLatency = %ld (%ld ms), added buffProc:%ld (%ld ms)\n",
 
2560
                stream->outputLatency,
 
2561
                (long)((stream->outputLatency*1000)/ sampleRate), 
 
2562
                PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor),
 
2563
                (long)((PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)*1000)/ sampleRate)
 
2564
                ));
 
2565
    }
 
2566
 
 
2567
    stream->asioHostApi = asioHostApi;
 
2568
    stream->framesPerHostCallback = framesPerHostBuffer;
 
2569
 
 
2570
    stream->inputChannelCount = inputChannelCount;
 
2571
    stream->outputChannelCount = outputChannelCount;
 
2572
    stream->postOutput = driverInfo->postOutput;
 
2573
    stream->isStopped = 1;
 
2574
    stream->isActive = 0;
 
2575
    
 
2576
    asioHostApi->openAsioDeviceIndex = asioDeviceIndex;
 
2577
 
 
2578
    theAsioStream = stream;
 
2579
    *s = (PaStream*)stream;
 
2580
 
 
2581
    return result;
 
2582
 
 
2583
error:
 
2584
    PA_DEBUG(("goto errored\n"));
 
2585
    if( stream )
 
2586
    {
 
2587
        if( stream->blockingState )
 
2588
        {
 
2589
            if( blockingBufferProcessorInited )
 
2590
                PaUtil_TerminateBufferProcessor( &stream->blockingState->bufferProcessor );
 
2591
 
 
2592
            if( stream->blockingState->writeRingBufferData )
 
2593
                PaUtil_FreeMemory( stream->blockingState->writeRingBufferData );
 
2594
            if( stream->blockingState->writeStreamBuffer )
 
2595
                PaUtil_FreeMemory( stream->blockingState->writeStreamBuffer );
 
2596
            if( blockingWriteBuffersReadyEventInitialized )
 
2597
                CloseHandle( stream->blockingState->writeBuffersReadyEvent );
 
2598
 
 
2599
            if( stream->blockingState->readRingBufferData )
 
2600
                PaUtil_FreeMemory( stream->blockingState->readRingBufferData );
 
2601
            if( stream->blockingState->readStreamBuffer )
 
2602
                PaUtil_FreeMemory( stream->blockingState->readStreamBuffer );
 
2603
            if( blockingReadFramesReadyEventInitialized )
 
2604
                CloseHandle( stream->blockingState->readFramesReadyEvent );
 
2605
 
 
2606
            PaUtil_FreeMemory( stream->blockingState );
 
2607
        }
 
2608
 
 
2609
        if( callbackBufferProcessorInited )
 
2610
            PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
 
2611
 
 
2612
        if( completedBuffersPlayedEventInited )
 
2613
            CloseHandle( stream->completedBuffersPlayedEvent );
 
2614
 
 
2615
        if( stream->asioBufferInfos )
 
2616
            PaUtil_FreeMemory( stream->asioBufferInfos );
 
2617
 
 
2618
        if( stream->asioChannelInfos )
 
2619
            PaUtil_FreeMemory( stream->asioChannelInfos );
 
2620
 
 
2621
        if( stream->bufferPtrs )
 
2622
            PaUtil_FreeMemory( stream->bufferPtrs );
 
2623
 
 
2624
        PaUtil_FreeMemory( stream );
 
2625
    }
 
2626
 
 
2627
    if( asioBuffersCreated )
 
2628
        ASIODisposeBuffers();
 
2629
 
 
2630
    if( asioIsInitialized )
 
2631
        {
 
2632
                UnloadAsioDriver();
 
2633
        }
 
2634
    return result;
 
2635
}
 
2636
 
 
2637
 
 
2638
/*
 
2639
    When CloseStream() is called, the multi-api layer ensures that
 
2640
    the stream has already been stopped or aborted.
 
2641
*/
 
2642
static PaError CloseStream( PaStream* s )
 
2643
{
 
2644
    PaError result = paNoError;
 
2645
    PaAsioStream *stream = (PaAsioStream*)s;
 
2646
 
 
2647
    /*
 
2648
        IMPLEMENT ME:
 
2649
            - additional stream closing + cleanup
 
2650
    */
 
2651
 
 
2652
    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
 
2653
    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
 
2654
 
 
2655
    stream->asioHostApi->openAsioDeviceIndex = paNoDevice;
 
2656
 
 
2657
    CloseHandle( stream->completedBuffersPlayedEvent );
 
2658
 
 
2659
    /* Using blocking i/o interface... */
 
2660
    if( stream->blockingState )
 
2661
    {
 
2662
        PaUtil_TerminateBufferProcessor( &stream->blockingState->bufferProcessor );
 
2663
 
 
2664
        if( stream->inputChannelCount ) {
 
2665
            PaUtil_FreeMemory( stream->blockingState->readRingBufferData );
 
2666
            PaUtil_FreeMemory( stream->blockingState->readStreamBuffer  );
 
2667
            CloseHandle( stream->blockingState->readFramesReadyEvent );
 
2668
        }
 
2669
        if( stream->outputChannelCount ) {
 
2670
            PaUtil_FreeMemory( stream->blockingState->writeRingBufferData );
 
2671
            PaUtil_FreeMemory( stream->blockingState->writeStreamBuffer );
 
2672
            CloseHandle( stream->blockingState->writeBuffersReadyEvent );
 
2673
        }
 
2674
 
 
2675
        PaUtil_FreeMemory( stream->blockingState );
 
2676
    }
 
2677
 
 
2678
    PaUtil_FreeMemory( stream->asioBufferInfos );
 
2679
    PaUtil_FreeMemory( stream->asioChannelInfos );
 
2680
    PaUtil_FreeMemory( stream->bufferPtrs );
 
2681
    PaUtil_FreeMemory( stream );
 
2682
 
 
2683
    ASIODisposeBuffers();
 
2684
    UnloadAsioDriver();
 
2685
 
 
2686
    theAsioStream = 0;
 
2687
 
 
2688
    return result;
 
2689
}
 
2690
 
 
2691
 
 
2692
static void bufferSwitch(long index, ASIOBool directProcess)
 
2693
{
 
2694
//TAKEN FROM THE ASIO SDK
 
2695
 
 
2696
    // the actual processing callback.
 
2697
    // Beware that this is normally in a seperate thread, hence be sure that
 
2698
    // you take care about thread synchronization. This is omitted here for
 
2699
    // simplicity.
 
2700
 
 
2701
    // as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs
 
2702
    // to be created though it will only set the timeInfo.samplePosition and
 
2703
    // timeInfo.systemTime fields and the according flags
 
2704
 
 
2705
    ASIOTime  timeInfo;
 
2706
    memset( &timeInfo, 0, sizeof (timeInfo) );
 
2707
 
 
2708
    // get the time stamp of the buffer, not necessary if no
 
2709
    // synchronization to other media is required
 
2710
    if( ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK)
 
2711
            timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
 
2712
 
 
2713
    // Call the real callback
 
2714
    bufferSwitchTimeInfo( &timeInfo, index, directProcess );
 
2715
}
 
2716
 
 
2717
 
 
2718
// conversion from 64 bit ASIOSample/ASIOTimeStamp to double float
 
2719
#if NATIVE_INT64
 
2720
    #define ASIO64toDouble(a)  (a)
 
2721
#else
 
2722
    const double twoRaisedTo32 = 4294967296.;
 
2723
    #define ASIO64toDouble(a)  ((a).lo + (a).hi * twoRaisedTo32)
 
2724
#endif
 
2725
 
 
2726
static ASIOTime *bufferSwitchTimeInfo( ASIOTime *timeInfo, long index, ASIOBool directProcess )
 
2727
{
 
2728
    // the actual processing callback.
 
2729
    // Beware that this is normally in a seperate thread, hence be sure that
 
2730
    // you take care about thread synchronization.
 
2731
 
 
2732
 
 
2733
    /* The SDK says the following about the directProcess flag:
 
2734
        suggests to the host whether it should immediately start processing
 
2735
        (directProcess == ASIOTrue), or whether its process should be deferred
 
2736
        because the call comes from a very low level (for instance, a high level
 
2737
        priority interrupt), and direct processing would cause timing instabilities for
 
2738
        the rest of the system. If in doubt, directProcess should be set to ASIOFalse.
 
2739
 
 
2740
        We just ignore directProcess. This could cause incompatibilities with
 
2741
        drivers which really don't want the audio processing to occur in this
 
2742
        callback, but none have been identified yet.
 
2743
    */
 
2744
 
 
2745
    (void) directProcess; /* suppress unused parameter warning */
 
2746
 
 
2747
#if 0
 
2748
    // store the timeInfo for later use
 
2749
    asioDriverInfo.tInfo = *timeInfo;
 
2750
 
 
2751
    // get the time stamp of the buffer, not necessary if no
 
2752
    // synchronization to other media is required
 
2753
 
 
2754
    if (timeInfo->timeInfo.flags & kSystemTimeValid)
 
2755
            asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime);
 
2756
    else
 
2757
            asioDriverInfo.nanoSeconds = 0;
 
2758
 
 
2759
    if (timeInfo->timeInfo.flags & kSamplePositionValid)
 
2760
            asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
 
2761
    else
 
2762
            asioDriverInfo.samples = 0;
 
2763
 
 
2764
    if (timeInfo->timeCode.flags & kTcValid)
 
2765
            asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
 
2766
    else
 
2767
            asioDriverInfo.tcSamples = 0;
 
2768
 
 
2769
    // get the system reference time
 
2770
    asioDriverInfo.sysRefTime = get_sys_reference_time();
 
2771
#endif
 
2772
 
 
2773
#if 0
 
2774
    // a few debug messages for the Windows device driver developer
 
2775
    // tells you the time when driver got its interrupt and the delay until the app receives
 
2776
    // the event notification.
 
2777
    static double last_samples = 0;
 
2778
    char tmp[128];
 
2779
    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));
 
2780
    OutputDebugString (tmp);
 
2781
    last_samples = asioDriverInfo.samples;
 
2782
#endif
 
2783
 
 
2784
 
 
2785
    if( !theAsioStream )
 
2786
        return 0L;
 
2787
 
 
2788
    // Keep sample position
 
2789
    // FIXME: asioDriverInfo.pahsc_NumFramesDone = timeInfo->timeInfo.samplePosition.lo;
 
2790
 
 
2791
 
 
2792
    // protect against reentrancy
 
2793
    if( PaAsio_AtomicIncrement(&theAsioStream->reenterCount) )
 
2794
    {
 
2795
        theAsioStream->reenterError++;
 
2796
        //DBUG(("bufferSwitchTimeInfo : reentrancy detection = %d\n", asioDriverInfo.reenterError));
 
2797
        return 0L;
 
2798
    }
 
2799
 
 
2800
    int buffersDone = 0;
 
2801
    
 
2802
    do
 
2803
    {
 
2804
        if( buffersDone > 0 )
 
2805
        {
 
2806
            // this is a reentered buffer, we missed processing it on time
 
2807
            // set the input overflow and output underflow flags as appropriate
 
2808
            
 
2809
            if( theAsioStream->inputChannelCount > 0 )
 
2810
                theAsioStream->callbackFlags |= paInputOverflow;
 
2811
                
 
2812
            if( theAsioStream->outputChannelCount > 0 )
 
2813
                theAsioStream->callbackFlags |= paOutputUnderflow;
 
2814
        }
 
2815
        else
 
2816
        {
 
2817
            if( theAsioStream->zeroOutput )
 
2818
            {
 
2819
                ZeroOutputBuffers( theAsioStream, index );
 
2820
 
 
2821
                // Finally if the driver supports the ASIOOutputReady() optimization,
 
2822
                // do it here, all data are in place
 
2823
                if( theAsioStream->postOutput )
 
2824
                    ASIOOutputReady();
 
2825
 
 
2826
                if( theAsioStream->stopProcessing )
 
2827
                {
 
2828
                    if( theAsioStream->stopPlayoutCount < 2 )
 
2829
                    {
 
2830
                        ++theAsioStream->stopPlayoutCount;
 
2831
                        if( theAsioStream->stopPlayoutCount == 2 )
 
2832
                        {
 
2833
                            theAsioStream->isActive = 0;
 
2834
                            if( theAsioStream->streamRepresentation.streamFinishedCallback != 0 )
 
2835
                                theAsioStream->streamRepresentation.streamFinishedCallback( theAsioStream->streamRepresentation.userData );
 
2836
                            theAsioStream->streamFinishedCallbackCalled = true;
 
2837
                            SetEvent( theAsioStream->completedBuffersPlayedEvent );
 
2838
                        }
 
2839
                    }
 
2840
                }
 
2841
            }
 
2842
            else
 
2843
            {
 
2844
 
 
2845
#if 0
 
2846
// test code to try to detect slip conditions... these may work on some systems
 
2847
// but neither of them work on the RME Digi96
 
2848
 
 
2849
// check that sample delta matches buffer size (otherwise we must have skipped
 
2850
// a buffer.
 
2851
static double last_samples = -512;
 
2852
double samples;
 
2853
//if( timeInfo->timeCode.flags & kTcValid )
 
2854
//    samples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
 
2855
//else
 
2856
    samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
 
2857
int delta = samples - last_samples;
 
2858
//printf( "%d\n", delta);
 
2859
last_samples = samples;
 
2860
 
 
2861
if( delta > theAsioStream->framesPerHostCallback )
 
2862
{
 
2863
    if( theAsioStream->inputChannelCount > 0 )
 
2864
        theAsioStream->callbackFlags |= paInputOverflow;
 
2865
 
 
2866
    if( theAsioStream->outputChannelCount > 0 )
 
2867
        theAsioStream->callbackFlags |= paOutputUnderflow;
 
2868
}
 
2869
 
 
2870
// check that the buffer index is not the previous index (which would indicate
 
2871
// that a buffer was skipped.
 
2872
static int previousIndex = 1;
 
2873
if( index == previousIndex )
 
2874
{
 
2875
    if( theAsioStream->inputChannelCount > 0 )
 
2876
        theAsioStream->callbackFlags |= paInputOverflow;
 
2877
 
 
2878
    if( theAsioStream->outputChannelCount > 0 )
 
2879
        theAsioStream->callbackFlags |= paOutputUnderflow;
 
2880
}
 
2881
previousIndex = index;
 
2882
#endif
 
2883
 
 
2884
                int i;
 
2885
 
 
2886
                PaUtil_BeginCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer );
 
2887
 
 
2888
                PaStreamCallbackTimeInfo paTimeInfo;
 
2889
 
 
2890
                // asio systemTime is supposed to be measured according to the same
 
2891
                // clock as timeGetTime
 
2892
                paTimeInfo.currentTime = (ASIO64toDouble( timeInfo->timeInfo.systemTime ) * .000000001);
 
2893
 
 
2894
                /* patch from Paul Boege */
 
2895
                paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime -
 
2896
                    ((double)theAsioStream->inputLatency/theAsioStream->streamRepresentation.streamInfo.sampleRate);
 
2897
 
 
2898
                paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime +
 
2899
                    ((double)theAsioStream->outputLatency/theAsioStream->streamRepresentation.streamInfo.sampleRate);
 
2900
 
 
2901
                /* old version is buggy because the buffer processor also adds in its latency to the time parameters
 
2902
                paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime - theAsioStream->streamRepresentation.streamInfo.inputLatency;
 
2903
                paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime + theAsioStream->streamRepresentation.streamInfo.outputLatency;
 
2904
                */
 
2905
 
 
2906
/* Disabled! Stopping and re-starting the stream causes an input overflow / output undeflow. S.Fischer */
 
2907
#if 0
 
2908
// detect underflows by checking inter-callback time > 2 buffer period
 
2909
static double previousTime = -1;
 
2910
if( previousTime > 0 ){
 
2911
 
 
2912
    double delta = paTimeInfo.currentTime - previousTime;
 
2913
 
 
2914
    if( delta >= 2. * (theAsioStream->framesPerHostCallback / theAsioStream->streamRepresentation.streamInfo.sampleRate) ){
 
2915
        if( theAsioStream->inputChannelCount > 0 )
 
2916
            theAsioStream->callbackFlags |= paInputOverflow;
 
2917
 
 
2918
        if( theAsioStream->outputChannelCount > 0 )
 
2919
            theAsioStream->callbackFlags |= paOutputUnderflow;
 
2920
    }
 
2921
}
 
2922
previousTime = paTimeInfo.currentTime;
 
2923
#endif
 
2924
 
 
2925
                // note that the above input and output times do not need to be
 
2926
                // adjusted for the latency of the buffer processor -- the buffer
 
2927
                // processor handles that.
 
2928
 
 
2929
                if( theAsioStream->inputBufferConverter )
 
2930
                {
 
2931
                    for( i=0; i<theAsioStream->inputChannelCount; i++ )
 
2932
                    {
 
2933
                        theAsioStream->inputBufferConverter( theAsioStream->inputBufferPtrs[index][i],
 
2934
                                theAsioStream->inputShift, theAsioStream->framesPerHostCallback );
 
2935
                    }
 
2936
                }
 
2937
 
 
2938
                PaUtil_BeginBufferProcessing( &theAsioStream->bufferProcessor, &paTimeInfo, theAsioStream->callbackFlags );
 
2939
 
 
2940
                /* reset status flags once they've been passed to the callback */
 
2941
                theAsioStream->callbackFlags = 0;
 
2942
 
 
2943
                PaUtil_SetInputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ );
 
2944
                for( i=0; i<theAsioStream->inputChannelCount; ++i )
 
2945
                    PaUtil_SetNonInterleavedInputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->inputBufferPtrs[index][i] );
 
2946
 
 
2947
                PaUtil_SetOutputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ );
 
2948
                for( i=0; i<theAsioStream->outputChannelCount; ++i )
 
2949
                    PaUtil_SetNonInterleavedOutputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->outputBufferPtrs[index][i] );
 
2950
 
 
2951
                int callbackResult;
 
2952
                if( theAsioStream->stopProcessing )
 
2953
                    callbackResult = paComplete;
 
2954
                else
 
2955
                    callbackResult = paContinue;
 
2956
                unsigned long framesProcessed = PaUtil_EndBufferProcessing( &theAsioStream->bufferProcessor, &callbackResult );
 
2957
 
 
2958
                if( theAsioStream->outputBufferConverter )
 
2959
                {
 
2960
                    for( i=0; i<theAsioStream->outputChannelCount; i++ )
 
2961
                    {
 
2962
                        theAsioStream->outputBufferConverter( theAsioStream->outputBufferPtrs[index][i],
 
2963
                                theAsioStream->outputShift, theAsioStream->framesPerHostCallback );
 
2964
                    }
 
2965
                }
 
2966
 
 
2967
                PaUtil_EndCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer, framesProcessed );
 
2968
 
 
2969
                // Finally if the driver supports the ASIOOutputReady() optimization,
 
2970
                // do it here, all data are in place
 
2971
                if( theAsioStream->postOutput )
 
2972
                    ASIOOutputReady();
 
2973
 
 
2974
                if( callbackResult == paContinue )
 
2975
                {
 
2976
                    /* nothing special to do */
 
2977
                }
 
2978
                else if( callbackResult == paAbort )
 
2979
                {
 
2980
                    /* finish playback immediately  */
 
2981
                    theAsioStream->isActive = 0;
 
2982
                    if( theAsioStream->streamRepresentation.streamFinishedCallback != 0 )
 
2983
                        theAsioStream->streamRepresentation.streamFinishedCallback( theAsioStream->streamRepresentation.userData );
 
2984
                    theAsioStream->streamFinishedCallbackCalled = true;
 
2985
                    SetEvent( theAsioStream->completedBuffersPlayedEvent );
 
2986
                    theAsioStream->zeroOutput = true;
 
2987
                }
 
2988
                else /* paComplete or other non-zero value indicating complete */
 
2989
                {
 
2990
                    /* Finish playback once currently queued audio has completed. */
 
2991
                    theAsioStream->stopProcessing = true;
 
2992
 
 
2993
                    if( PaUtil_IsBufferProcessorOutputEmpty( &theAsioStream->bufferProcessor ) )
 
2994
                    {
 
2995
                        theAsioStream->zeroOutput = true;
 
2996
                        theAsioStream->stopPlayoutCount = 0;
 
2997
                    }
 
2998
                }
 
2999
            }
 
3000
        }
 
3001
        
 
3002
        ++buffersDone;
 
3003
    }while( PaAsio_AtomicDecrement(&theAsioStream->reenterCount) >= 0 );
 
3004
 
 
3005
    return 0L;
 
3006
}
 
3007
 
 
3008
 
 
3009
static void sampleRateChanged(ASIOSampleRate sRate)
 
3010
{
 
3011
    // TAKEN FROM THE ASIO SDK
 
3012
    // do whatever you need to do if the sample rate changed
 
3013
    // usually this only happens during external sync.
 
3014
    // Audio processing is not stopped by the driver, actual sample rate
 
3015
    // might not have even changed, maybe only the sample rate status of an
 
3016
    // AES/EBU or S/PDIF digital input at the audio device.
 
3017
    // You might have to update time/sample related conversion routines, etc.
 
3018
 
 
3019
    (void) sRate; /* unused parameter */
 
3020
    PA_DEBUG( ("sampleRateChanged : %d \n", sRate));
 
3021
}
 
3022
 
 
3023
static long asioMessages(long selector, long value, void* message, double* opt)
 
3024
{
 
3025
// TAKEN FROM THE ASIO SDK
 
3026
    // currently the parameters "value", "message" and "opt" are not used.
 
3027
    long ret = 0;
 
3028
 
 
3029
    (void) message; /* unused parameters */
 
3030
    (void) opt;
 
3031
 
 
3032
    PA_DEBUG( ("asioMessages : %d , %d \n", selector, value));
 
3033
 
 
3034
    switch(selector)
 
3035
    {
 
3036
        case kAsioSelectorSupported:
 
3037
            if(value == kAsioResetRequest
 
3038
            || value == kAsioEngineVersion
 
3039
            || value == kAsioResyncRequest
 
3040
            || value == kAsioLatenciesChanged
 
3041
            // the following three were added for ASIO 2.0, you don't necessarily have to support them
 
3042
            || value == kAsioSupportsTimeInfo
 
3043
            || value == kAsioSupportsTimeCode
 
3044
            || value == kAsioSupportsInputMonitor)
 
3045
                    ret = 1L;
 
3046
            break;
 
3047
 
 
3048
        case kAsioBufferSizeChange:
 
3049
            //printf("kAsioBufferSizeChange \n");
 
3050
            break;
 
3051
 
 
3052
        case kAsioResetRequest:
 
3053
            // defer the task and perform the reset of the driver during the next "safe" situation
 
3054
            // You cannot reset the driver right now, as this code is called from the driver.
 
3055
            // Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction
 
3056
            // Afterwards you initialize the driver again.
 
3057
 
 
3058
            /*FIXME: commented the next line out */
 
3059
            //asioDriverInfo.stopped;  // In this sample the processing will just stop
 
3060
            ret = 1L;
 
3061
            break;
 
3062
 
 
3063
        case kAsioResyncRequest:
 
3064
            // This informs the application, that the driver encountered some non fatal data loss.
 
3065
            // It is used for synchronization purposes of different media.
 
3066
            // Added mainly to work around the Win16Mutex problems in Windows 95/98 with the
 
3067
            // Windows Multimedia system, which could loose data because the Mutex was hold too long
 
3068
            // by another thread.
 
3069
            // However a driver can issue it in other situations, too.
 
3070
            ret = 1L;
 
3071
            break;
 
3072
 
 
3073
        case kAsioLatenciesChanged:
 
3074
            // This will inform the host application that the drivers were latencies changed.
 
3075
            // Beware, it this does not mean that the buffer sizes have changed!
 
3076
            // You might need to update internal delay data.
 
3077
            ret = 1L;
 
3078
            //printf("kAsioLatenciesChanged \n");
 
3079
            break;
 
3080
 
 
3081
        case kAsioEngineVersion:
 
3082
            // return the supported ASIO version of the host application
 
3083
            // If a host applications does not implement this selector, ASIO 1.0 is assumed
 
3084
            // by the driver
 
3085
            ret = 2L;
 
3086
            break;
 
3087
 
 
3088
        case kAsioSupportsTimeInfo:
 
3089
            // informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback
 
3090
            // is supported.
 
3091
            // For compatibility with ASIO 1.0 drivers the host application should always support
 
3092
            // the "old" bufferSwitch method, too.
 
3093
            ret = 1;
 
3094
            break;
 
3095
 
 
3096
        case kAsioSupportsTimeCode:
 
3097
            // informs the driver wether application is interested in time code info.
 
3098
            // If an application does not need to know about time code, the driver has less work
 
3099
            // to do.
 
3100
            ret = 0;
 
3101
            break;
 
3102
    }
 
3103
    return ret;
 
3104
}
 
3105
 
 
3106
 
 
3107
static PaError StartStream( PaStream *s )
 
3108
{
 
3109
    PaError result = paNoError;
 
3110
    PaAsioStream *stream = (PaAsioStream*)s;
 
3111
    PaAsioStreamBlockingState *blockingState = stream->blockingState;
 
3112
    ASIOError asioError;
 
3113
 
 
3114
    if( stream->outputChannelCount > 0 )
 
3115
    {
 
3116
        ZeroOutputBuffers( stream, 0 );
 
3117
        ZeroOutputBuffers( stream, 1 );
 
3118
    }
 
3119
 
 
3120
    PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
 
3121
    stream->stopProcessing = false;
 
3122
    stream->zeroOutput = false;
 
3123
 
 
3124
    /* Reentrancy counter initialisation */
 
3125
    stream->reenterCount = -1;
 
3126
    stream->reenterError = 0;
 
3127
 
 
3128
    stream->callbackFlags = 0;
 
3129
 
 
3130
    if( ResetEvent( stream->completedBuffersPlayedEvent ) == 0 )
 
3131
    {
 
3132
        result = paUnanticipatedHostError;
 
3133
        PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
 
3134
    }
 
3135
 
 
3136
 
 
3137
    /* Using blocking i/o interface... */
 
3138
    if( blockingState )
 
3139
    {
 
3140
        /* Reset blocking i/o buffer processor. */
 
3141
        PaUtil_ResetBufferProcessor( &blockingState->bufferProcessor );
 
3142
 
 
3143
        /* If we're about to process some input data. */
 
3144
        if( stream->inputChannelCount )
 
3145
        {
 
3146
            /* Reset callback-ReadStream sync event. */
 
3147
            if( ResetEvent( blockingState->readFramesReadyEvent ) == 0 )
 
3148
            {
 
3149
                result = paUnanticipatedHostError;
 
3150
                PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
 
3151
            }
 
3152
 
 
3153
            /* Flush blocking i/o ring buffer. */
 
3154
            PaUtil_FlushRingBuffer( &blockingState->readRingBuffer );
 
3155
            (*blockingState->bufferProcessor.inputZeroer)( blockingState->readRingBuffer.buffer, 1, blockingState->bufferProcessor.inputChannelCount * blockingState->readRingBuffer.bufferSize );
 
3156
        }
 
3157
 
 
3158
        /* If we're about to process some output data. */
 
3159
        if( stream->outputChannelCount )
 
3160
        {
 
3161
            /* Reset callback-WriteStream sync event. */
 
3162
            if( ResetEvent( blockingState->writeBuffersReadyEvent ) == 0 )
 
3163
            {
 
3164
                result = paUnanticipatedHostError;
 
3165
                PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
 
3166
            }
 
3167
 
 
3168
            /* Flush blocking i/o ring buffer. */
 
3169
            PaUtil_FlushRingBuffer( &blockingState->writeRingBuffer );
 
3170
            (*blockingState->bufferProcessor.outputZeroer)( blockingState->writeRingBuffer.buffer, 1, blockingState->bufferProcessor.outputChannelCount * blockingState->writeRingBuffer.bufferSize );
 
3171
 
 
3172
            /* Initialize the output ring buffer to "silence". */
 
3173
            PaUtil_AdvanceRingBufferWriteIndex( &blockingState->writeRingBuffer, blockingState->writeRingBufferInitialFrames );
 
3174
        }
 
3175
 
 
3176
        /* Clear requested frames / buffers count. */
 
3177
        blockingState->writeBuffersRequested     = 0;
 
3178
        blockingState->readFramesRequested       = 0;
 
3179
        blockingState->writeBuffersRequestedFlag = FALSE;
 
3180
        blockingState->readFramesRequestedFlag   = FALSE;
 
3181
        blockingState->outputUnderflowFlag       = FALSE;
 
3182
        blockingState->inputOverflowFlag         = FALSE;
 
3183
        blockingState->stopFlag                  = FALSE;
 
3184
    }
 
3185
 
 
3186
 
 
3187
    if( result == paNoError )
 
3188
    {
 
3189
        assert( theAsioStream == stream ); /* theAsioStream should be set correctly in OpenStream */
 
3190
 
 
3191
        /* initialize these variables before the callback has a chance to be invoked */
 
3192
        stream->isStopped = 0;
 
3193
        stream->isActive = 1;
 
3194
        stream->streamFinishedCallbackCalled = false;
 
3195
 
 
3196
        asioError = ASIOStart();
 
3197
        if( asioError != ASE_OK )
 
3198
        {
 
3199
            stream->isStopped = 1;
 
3200
            stream->isActive = 0;
 
3201
 
 
3202
            result = paUnanticipatedHostError;
 
3203
            PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
 
3204
        }
 
3205
    }
 
3206
 
 
3207
    return result;
 
3208
}
 
3209
 
 
3210
static void EnsureCallbackHasCompleted( PaAsioStream *stream )
 
3211
{
 
3212
    // make sure that the callback is not still in-flight after ASIOStop()
 
3213
    // returns. This has been observed to happen on the Hoontech DSP24 for
 
3214
    // example.
 
3215
    int count = 2000;  // only wait for 2 seconds, rather than hanging.
 
3216
    while( stream->reenterCount != -1 && count > 0 )
 
3217
    {
 
3218
        Sleep(1);
 
3219
        --count;
 
3220
    }
 
3221
}
 
3222
 
 
3223
static PaError StopStream( PaStream *s )
 
3224
{
 
3225
    PaError result = paNoError;
 
3226
    PaAsioStream *stream = (PaAsioStream*)s;
 
3227
    PaAsioStreamBlockingState *blockingState = stream->blockingState;
 
3228
    ASIOError asioError;
 
3229
 
 
3230
    if( stream->isActive )
 
3231
    {
 
3232
        /* If blocking i/o output is in use */
 
3233
        if( blockingState && stream->outputChannelCount )
 
3234
        {
 
3235
            /* Request the whole output buffer to be available. */
 
3236
            blockingState->writeBuffersRequested = blockingState->writeRingBuffer.bufferSize;
 
3237
            /* Signalize that additional buffers are need. */
 
3238
            blockingState->writeBuffersRequestedFlag = TRUE;
 
3239
            /* Set flag to indicate the playback is to be stopped. */
 
3240
            blockingState->stopFlag = TRUE;
 
3241
 
 
3242
            /* Wait until requested number of buffers has been freed. Time
 
3243
               out after twice the blocking i/o ouput buffer could have
 
3244
               been consumed. */
 
3245
            DWORD timeout = (DWORD)( 2 * blockingState->writeRingBuffer.bufferSize * 1000
 
3246
                                       / stream->streamRepresentation.streamInfo.sampleRate );
 
3247
            DWORD waitResult = WaitForSingleObject( blockingState->writeBuffersReadyEvent, timeout );
 
3248
 
 
3249
            /* If something seriously went wrong... */
 
3250
            if( waitResult == WAIT_FAILED )
 
3251
            {
 
3252
                PA_DEBUG(("WaitForSingleObject() failed in StopStream()\n"));
 
3253
                result = paUnanticipatedHostError;
 
3254
                PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
 
3255
            }
 
3256
            else if( waitResult == WAIT_TIMEOUT )
 
3257
            {
 
3258
                PA_DEBUG(("WaitForSingleObject() timed out in StopStream()\n"));
 
3259
                result = paTimedOut;
 
3260
            }
 
3261
        }
 
3262
 
 
3263
        stream->stopProcessing = true;
 
3264
 
 
3265
        /* wait for the stream to finish playing out enqueued buffers.
 
3266
            timeout after four times the stream latency.
 
3267
 
 
3268
            @todo should use a better time out value - if the user buffer
 
3269
            length is longer than the asio buffer size then that should
 
3270
            be taken into account.
 
3271
        */
 
3272
        if( WaitForSingleObject( stream->completedBuffersPlayedEvent,
 
3273
                (DWORD)(stream->streamRepresentation.streamInfo.outputLatency * 1000. * 4.) )
 
3274
                    == WAIT_TIMEOUT )
 
3275
        {
 
3276
            PA_DEBUG(("WaitForSingleObject() timed out in StopStream()\n" ));
 
3277
        }
 
3278
    }
 
3279
 
 
3280
    asioError = ASIOStop();
 
3281
    if( asioError == ASE_OK )
 
3282
    {
 
3283
        EnsureCallbackHasCompleted( stream );
 
3284
    }
 
3285
    else
 
3286
    {
 
3287
        result = paUnanticipatedHostError;
 
3288
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
 
3289
    }
 
3290
 
 
3291
    stream->isStopped = 1;
 
3292
    stream->isActive = 0;
 
3293
 
 
3294
    if( !stream->streamFinishedCallbackCalled )
 
3295
    {
 
3296
        if( stream->streamRepresentation.streamFinishedCallback != 0 )
 
3297
            stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
 
3298
    }
 
3299
 
 
3300
    return result;
 
3301
}
 
3302
 
 
3303
static PaError AbortStream( PaStream *s )
 
3304
{
 
3305
    PaError result = paNoError;
 
3306
    PaAsioStream *stream = (PaAsioStream*)s;
 
3307
    ASIOError asioError;
 
3308
 
 
3309
    stream->zeroOutput = true;
 
3310
 
 
3311
    asioError = ASIOStop();
 
3312
    if( asioError == ASE_OK )
 
3313
    {
 
3314
        EnsureCallbackHasCompleted( stream );
 
3315
    }
 
3316
    else
 
3317
    {
 
3318
        result = paUnanticipatedHostError;
 
3319
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
 
3320
    }
 
3321
 
 
3322
    stream->isStopped = 1;
 
3323
    stream->isActive = 0;
 
3324
 
 
3325
    if( !stream->streamFinishedCallbackCalled )
 
3326
    {
 
3327
        if( stream->streamRepresentation.streamFinishedCallback != 0 )
 
3328
            stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
 
3329
    }
 
3330
 
 
3331
    return result;
 
3332
}
 
3333
 
 
3334
 
 
3335
static PaError IsStreamStopped( PaStream *s )
 
3336
{
 
3337
    PaAsioStream *stream = (PaAsioStream*)s;
 
3338
    
 
3339
    return stream->isStopped;
 
3340
}
 
3341
 
 
3342
 
 
3343
static PaError IsStreamActive( PaStream *s )
 
3344
{
 
3345
    PaAsioStream *stream = (PaAsioStream*)s;
 
3346
 
 
3347
    return stream->isActive;
 
3348
}
 
3349
 
 
3350
 
 
3351
static PaTime GetStreamTime( PaStream *s )
 
3352
{
 
3353
    (void) s; /* unused parameter */
 
3354
    return (double)timeGetTime() * .001;
 
3355
}
 
3356
 
 
3357
 
 
3358
static double GetStreamCpuLoad( PaStream* s )
 
3359
{
 
3360
    PaAsioStream *stream = (PaAsioStream*)s;
 
3361
 
 
3362
    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
 
3363
}
 
3364
 
 
3365
 
 
3366
/*
 
3367
    As separate stream interfaces are used for blocking and callback
 
3368
    streams, the following functions can be guaranteed to only be called
 
3369
    for blocking streams.
 
3370
*/
 
3371
 
 
3372
static PaError ReadStream( PaStream      *s     ,
 
3373
                           void          *buffer,
 
3374
                           unsigned long  frames )
 
3375
{
 
3376
    PaError result = paNoError; /* Initial return value. */
 
3377
    PaAsioStream *stream = (PaAsioStream*)s; /* The PA ASIO stream. */
 
3378
 
 
3379
    /* Pointer to the blocking i/o data struct. */
 
3380
    PaAsioStreamBlockingState *blockingState = stream->blockingState;
 
3381
 
 
3382
    /* Get blocking i/o buffer processor and ring buffer pointers. */
 
3383
    PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor;
 
3384
    PaUtilRingBuffer      *pRb = &blockingState->readRingBuffer;
 
3385
 
 
3386
    /* Ring buffer segment(s) used for writing. */
 
3387
    void *pRingBufferData1st = NULL; /* First segment. (Mandatory) */
 
3388
    void *pRingBufferData2nd = NULL; /* Second segment. (Optional) */
 
3389
 
 
3390
    /* Number of frames per ring buffer segment. */
 
3391
    long lRingBufferSize1st = 0; /* First segment. (Mandatory) */
 
3392
    long lRingBufferSize2nd = 0; /* Second segment. (Optional) */
 
3393
 
 
3394
    /* Get number of frames to be processed per data block. */
 
3395
    unsigned long lFramesPerBlock = stream->bufferProcessor.framesPerUserBuffer;
 
3396
    /* Actual number of frames that has been copied into the ring buffer. */
 
3397
    unsigned long lFramesCopied = 0;
 
3398
    /* The number of remaining unprocessed dtat frames. */
 
3399
    unsigned long lFramesRemaining = frames;
 
3400
 
 
3401
    /* Copy the input argument to avoid pointer increment! */
 
3402
    const void *userBuffer;
 
3403
    unsigned int i; /* Just a counter. */
 
3404
 
 
3405
    /* About the time, needed to process 8 data blocks. */
 
3406
    DWORD timeout = (DWORD)( 8 * lFramesPerBlock * 1000 / stream->streamRepresentation.streamInfo.sampleRate );
 
3407
    DWORD waitResult = 0;
 
3408
 
 
3409
 
 
3410
    /* Check if the stream is still available ready to gather new data. */
 
3411
    if( blockingState->stopFlag || !stream->isActive )
 
3412
    {
 
3413
        PA_DEBUG(("Warning! Stream no longer available for reading in ReadStream()\n"));
 
3414
        result = paStreamIsStopped;
 
3415
        return result;
 
3416
    }
 
3417
 
 
3418
    /* If the stream is a input stream. */
 
3419
    if( stream->inputChannelCount )
 
3420
    {
 
3421
        /* Prepare buffer access. */
 
3422
        if( !pBp->userOutputIsInterleaved )
 
3423
        {
 
3424
            userBuffer = blockingState->readStreamBuffer;
 
3425
            for( i = 0; i<pBp->inputChannelCount; ++i )
 
3426
            {
 
3427
                ((void**)userBuffer)[i] = ((void**)buffer)[i];
 
3428
            }
 
3429
        } /* Use the unchanged buffer. */
 
3430
        else { userBuffer = buffer; }
 
3431
 
 
3432
        do /* Internal block processing for too large user data buffers. */
 
3433
        {
 
3434
            /* Get the size of the current data block to be processed. */
 
3435
            lFramesPerBlock =(lFramesPerBlock < lFramesRemaining)
 
3436
                            ? lFramesPerBlock : lFramesRemaining;
 
3437
            /* Use predefined block size for as long there are enough
 
3438
               buffers available, thereafter reduce the processing block
 
3439
               size to match the number of remaining buffers. So the final
 
3440
               data block is processed although it may be incomplete. */
 
3441
 
 
3442
            /* If the available amount of data frames is insufficient. */
 
3443
            if( PaUtil_GetRingBufferReadAvailable(pRb) < (long) lFramesPerBlock )
 
3444
            {
 
3445
                /* Make sure, the event isn't already set! */
 
3446
                /* ResetEvent( blockingState->readFramesReadyEvent ); */
 
3447
 
 
3448
                /* Set the number of requested buffers. */
 
3449
                blockingState->readFramesRequested = lFramesPerBlock;
 
3450
 
 
3451
                /* Signalize that additional buffers are need. */
 
3452
                blockingState->readFramesRequestedFlag = TRUE;
 
3453
 
 
3454
                /* Wait until requested number of buffers has been freed. */
 
3455
                waitResult = WaitForSingleObject( blockingState->readFramesReadyEvent, timeout );
 
3456
 
 
3457
                /* If something seriously went wrong... */
 
3458
                if( waitResult == WAIT_FAILED )
 
3459
                {
 
3460
                    PA_DEBUG(("WaitForSingleObject() failed in ReadStream()\n"));
 
3461
                    result = paUnanticipatedHostError;
 
3462
                    PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
 
3463
                    return result;
 
3464
                }
 
3465
                else if( waitResult == WAIT_TIMEOUT )
 
3466
                {
 
3467
                    PA_DEBUG(("WaitForSingleObject() timed out in ReadStream()\n"));
 
3468
 
 
3469
                    /* If block processing has stopped, abort! */
 
3470
                    if( blockingState->stopFlag ) { return result = paStreamIsStopped; }
 
3471
 
 
3472
                    /* If a timeout is encountered, give up eventually. */
 
3473
                    return result = paTimedOut;
 
3474
                }
 
3475
            }
 
3476
            /* Now, the ring buffer contains the required amount of data
 
3477
               frames.
 
3478
               (Therefor we don't need to check the return argument of
 
3479
               PaUtil_GetRingBufferReadRegions(). ;-) )
 
3480
            */
 
3481
 
 
3482
            /* Retrieve pointer(s) to the ring buffer's current write
 
3483
               position(s). If the first buffer segment is too small to
 
3484
               store the requested number of bytes, an additional second
 
3485
               segment is returned. Otherwise, i.e. if the first segment
 
3486
               is large enough, the second segment's pointer will be NULL.
 
3487
            */
 
3488
            PaUtil_GetRingBufferReadRegions(pRb                ,
 
3489
                                            lFramesPerBlock    ,
 
3490
                                            &pRingBufferData1st,
 
3491
                                            &lRingBufferSize1st,
 
3492
                                            &pRingBufferData2nd,
 
3493
                                            &lRingBufferSize2nd);
 
3494
 
 
3495
            /* Set number of frames to be copied from the ring buffer. */
 
3496
            PaUtil_SetInputFrameCount( pBp, lRingBufferSize1st ); 
 
3497
            /* Setup ring buffer access. */
 
3498
            PaUtil_SetInterleavedInputChannels(pBp               ,  /* Buffer processor. */
 
3499
                                               0                 ,  /* The first channel's index. */
 
3500
                                               pRingBufferData1st,  /* First ring buffer segment. */
 
3501
                                               0                 ); /* Use all available channels. */
 
3502
 
 
3503
            /* If a second ring buffer segment is required. */
 
3504
            if( lRingBufferSize2nd ) {
 
3505
                /* Set number of frames to be copied from the ring buffer. */
 
3506
                PaUtil_Set2ndInputFrameCount( pBp, lRingBufferSize2nd );
 
3507
                /* Setup ring buffer access. */
 
3508
                PaUtil_Set2ndInterleavedInputChannels(pBp               ,  /* Buffer processor. */
 
3509
                                                      0                 ,  /* The first channel's index. */
 
3510
                                                      pRingBufferData2nd,  /* Second ring buffer segment. */
 
3511
                                                      0                 ); /* Use all available channels. */
 
3512
            }
 
3513
 
 
3514
            /* Let the buffer processor handle "copy and conversion" and
 
3515
               update the ring buffer indices manually. */
 
3516
            lFramesCopied = PaUtil_CopyInput( pBp, &buffer, lFramesPerBlock );
 
3517
            PaUtil_AdvanceRingBufferReadIndex( pRb, lFramesCopied );
 
3518
 
 
3519
            /* Decrease number of unprocessed frames. */
 
3520
            lFramesRemaining -= lFramesCopied;
 
3521
 
 
3522
        } /* Continue with the next data chunk. */
 
3523
        while( lFramesRemaining );
 
3524
 
 
3525
 
 
3526
        /* If there has been an input overflow within the callback */
 
3527
        if( blockingState->inputOverflowFlag )
 
3528
        {
 
3529
            blockingState->inputOverflowFlag = FALSE;
 
3530
 
 
3531
            /* Return the corresponding error code. */
 
3532
            result = paInputOverflowed;
 
3533
        }
 
3534
 
 
3535
    } /* If this is not an input stream. */
 
3536
    else {
 
3537
        result = paCanNotReadFromAnOutputOnlyStream;
 
3538
    }
 
3539
 
 
3540
    return result;
 
3541
}
 
3542
 
 
3543
static PaError WriteStream( PaStream      *s     ,
 
3544
                            const void    *buffer,
 
3545
                            unsigned long  frames )
 
3546
{
 
3547
    PaError result = paNoError; /* Initial return value. */
 
3548
    PaAsioStream *stream = (PaAsioStream*)s; /* The PA ASIO stream. */
 
3549
 
 
3550
    /* Pointer to the blocking i/o data struct. */
 
3551
    PaAsioStreamBlockingState *blockingState = stream->blockingState;
 
3552
 
 
3553
    /* Get blocking i/o buffer processor and ring buffer pointers. */
 
3554
    PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor;
 
3555
    PaUtilRingBuffer      *pRb = &blockingState->writeRingBuffer;
 
3556
 
 
3557
    /* Ring buffer segment(s) used for writing. */
 
3558
    void *pRingBufferData1st = NULL; /* First segment. (Mandatory) */
 
3559
    void *pRingBufferData2nd = NULL; /* Second segment. (Optional) */
 
3560
 
 
3561
    /* Number of frames per ring buffer segment. */
 
3562
    long lRingBufferSize1st = 0; /* First segment. (Mandatory) */
 
3563
    long lRingBufferSize2nd = 0; /* Second segment. (Optional) */
 
3564
 
 
3565
    /* Get number of frames to be processed per data block. */
 
3566
    unsigned long lFramesPerBlock = stream->bufferProcessor.framesPerUserBuffer;
 
3567
    /* Actual number of frames that has been copied into the ring buffer. */
 
3568
    unsigned long lFramesCopied = 0;
 
3569
    /* The number of remaining unprocessed dtat frames. */
 
3570
    unsigned long lFramesRemaining = frames;
 
3571
 
 
3572
    /* About the time, needed to process 8 data blocks. */
 
3573
    DWORD timeout = (DWORD)( 8 * lFramesPerBlock * 1000 / stream->streamRepresentation.streamInfo.sampleRate );
 
3574
    DWORD waitResult = 0;
 
3575
 
 
3576
    /* Copy the input argument to avoid pointer increment! */
 
3577
    const void *userBuffer;
 
3578
    unsigned int i; /* Just a counter. */
 
3579
 
 
3580
 
 
3581
    /* Check if the stream ist still available ready to recieve new data. */
 
3582
    if( blockingState->stopFlag || !stream->isActive )
 
3583
    {
 
3584
        PA_DEBUG(("Warning! Stream no longer available for writing in WriteStream()\n"));
 
3585
        result = paStreamIsStopped;
 
3586
        return result;
 
3587
    }
 
3588
 
 
3589
    /* If the stream is a output stream. */
 
3590
    if( stream->outputChannelCount )
 
3591
    {
 
3592
        /* Prepare buffer access. */
 
3593
        if( !pBp->userOutputIsInterleaved )
 
3594
        {
 
3595
            userBuffer = blockingState->writeStreamBuffer;
 
3596
            for( i = 0; i<pBp->outputChannelCount; ++i )
 
3597
            {
 
3598
                ((const void**)userBuffer)[i] = ((const void**)buffer)[i];
 
3599
            }
 
3600
        } /* Use the unchanged buffer. */
 
3601
        else { userBuffer = buffer; }
 
3602
 
 
3603
 
 
3604
        do /* Internal block processing for too large user data buffers. */
 
3605
        {
 
3606
            /* Get the size of the current data block to be processed. */
 
3607
            lFramesPerBlock =(lFramesPerBlock < lFramesRemaining)
 
3608
                            ? lFramesPerBlock : lFramesRemaining;
 
3609
            /* Use predefined block size for as long there are enough
 
3610
               frames available, thereafter reduce the processing block
 
3611
               size to match the number of remaining frames. So the final
 
3612
               data block is processed although it may be incomplete. */
 
3613
 
 
3614
            /* If the available amount of buffers is insufficient. */
 
3615
            if( PaUtil_GetRingBufferWriteAvailable(pRb) < (long) lFramesPerBlock )
 
3616
            {
 
3617
                /* Make sure, the event isn't already set! */
 
3618
                /* ResetEvent( blockingState->writeBuffersReadyEvent ); */
 
3619
 
 
3620
                /* Set the number of requested buffers. */
 
3621
                blockingState->writeBuffersRequested = lFramesPerBlock;
 
3622
 
 
3623
                /* Signalize that additional buffers are need. */
 
3624
                blockingState->writeBuffersRequestedFlag = TRUE;
 
3625
 
 
3626
                /* Wait until requested number of buffers has been freed. */
 
3627
                waitResult = WaitForSingleObject( blockingState->writeBuffersReadyEvent, timeout );
 
3628
 
 
3629
                /* If something seriously went wrong... */
 
3630
                if( waitResult == WAIT_FAILED )
 
3631
                {
 
3632
                    PA_DEBUG(("WaitForSingleObject() failed in WriteStream()\n"));
 
3633
                    result = paUnanticipatedHostError;
 
3634
                    PA_ASIO_SET_LAST_SYSTEM_ERROR( GetLastError() );
 
3635
                    return result;
 
3636
                }
 
3637
                else if( waitResult == WAIT_TIMEOUT )
 
3638
                {
 
3639
                    PA_DEBUG(("WaitForSingleObject() timed out in WriteStream()\n"));
 
3640
 
 
3641
                    /* If block processing has stopped, abort! */
 
3642
                    if( blockingState->stopFlag ) { return result = paStreamIsStopped; }
 
3643
                    
 
3644
                    /* If a timeout is encountered, give up eventually. */
 
3645
                    return result = paTimedOut;
 
3646
                }
 
3647
            }
 
3648
            /* Now, the ring buffer contains the required amount of free
 
3649
               space to store the provided number of data frames.
 
3650
               (Therefor we don't need to check the return argument of
 
3651
               PaUtil_GetRingBufferWriteRegions(). ;-) )
 
3652
            */
 
3653
 
 
3654
            /* Retrieve pointer(s) to the ring buffer's current write
 
3655
               position(s). If the first buffer segment is too small to
 
3656
               store the requested number of bytes, an additional second
 
3657
               segment is returned. Otherwise, i.e. if the first segment
 
3658
               is large enough, the second segment's pointer will be NULL.
 
3659
            */
 
3660
            PaUtil_GetRingBufferWriteRegions(pRb                ,
 
3661
                                             lFramesPerBlock    ,
 
3662
                                             &pRingBufferData1st,
 
3663
                                             &lRingBufferSize1st,
 
3664
                                             &pRingBufferData2nd,
 
3665
                                             &lRingBufferSize2nd);
 
3666
 
 
3667
            /* Set number of frames to be copied to the ring buffer. */
 
3668
            PaUtil_SetOutputFrameCount( pBp, lRingBufferSize1st ); 
 
3669
            /* Setup ring buffer access. */
 
3670
            PaUtil_SetInterleavedOutputChannels(pBp               ,  /* Buffer processor. */
 
3671
                                                0                 ,  /* The first channel's index. */
 
3672
                                                pRingBufferData1st,  /* First ring buffer segment. */
 
3673
                                                0                 ); /* Use all available channels. */
 
3674
 
 
3675
            /* If a second ring buffer segment is required. */
 
3676
            if( lRingBufferSize2nd ) {
 
3677
                /* Set number of frames to be copied to the ring buffer. */
 
3678
                PaUtil_Set2ndOutputFrameCount( pBp, lRingBufferSize2nd );
 
3679
                /* Setup ring buffer access. */
 
3680
                PaUtil_Set2ndInterleavedOutputChannels(pBp               ,  /* Buffer processor. */
 
3681
                                                       0                 ,  /* The first channel's index. */
 
3682
                                                       pRingBufferData2nd,  /* Second ring buffer segment. */
 
3683
                                                       0                 ); /* Use all available channels. */
 
3684
            }
 
3685
 
 
3686
            /* Let the buffer processor handle "copy and conversion" and
 
3687
               update the ring buffer indices manually. */
 
3688
            lFramesCopied = PaUtil_CopyOutput( pBp, &userBuffer, lFramesPerBlock );
 
3689
            PaUtil_AdvanceRingBufferWriteIndex( pRb, lFramesCopied );
 
3690
 
 
3691
            /* Decrease number of unprocessed frames. */
 
3692
            lFramesRemaining -= lFramesCopied;
 
3693
 
 
3694
        } /* Continue with the next data chunk. */
 
3695
        while( lFramesRemaining );
 
3696
 
 
3697
 
 
3698
        /* If there has been an output underflow within the callback */
 
3699
        if( blockingState->outputUnderflowFlag )
 
3700
        {
 
3701
            blockingState->outputUnderflowFlag = FALSE;
 
3702
 
 
3703
            /* Return the corresponding error code. */
 
3704
            result = paOutputUnderflowed;
 
3705
        }
 
3706
 
 
3707
    } /* If this is not an output stream. */
 
3708
    else
 
3709
    {
 
3710
        result = paCanNotWriteToAnInputOnlyStream;
 
3711
    }
 
3712
 
 
3713
    return result;
 
3714
}
 
3715
 
 
3716
 
 
3717
static signed long GetStreamReadAvailable( PaStream* s )
 
3718
{
 
3719
    PaAsioStream *stream = (PaAsioStream*)s;
 
3720
 
 
3721
    /* Call buffer utility routine to get the number of available frames. */
 
3722
    return PaUtil_GetRingBufferReadAvailable( &stream->blockingState->readRingBuffer );
 
3723
}
 
3724
 
 
3725
 
 
3726
static signed long GetStreamWriteAvailable( PaStream* s )
 
3727
{
 
3728
    PaAsioStream *stream = (PaAsioStream*)s;
 
3729
 
 
3730
    /* Call buffer utility routine to get the number of empty buffers. */
 
3731
    return PaUtil_GetRingBufferWriteAvailable( &stream->blockingState->writeRingBuffer );
 
3732
}
 
3733
 
 
3734
 
 
3735
/* This routine will be called by the PortAudio engine when audio is needed.
 
3736
** It may called at interrupt level on some machines so don't do anything
 
3737
** that could mess up the system like calling malloc() or free().
 
3738
*/
 
3739
static int BlockingIoPaCallback(const void                     *inputBuffer    ,
 
3740
                                      void                     *outputBuffer   ,
 
3741
                                      unsigned long             framesPerBuffer,
 
3742
                                const PaStreamCallbackTimeInfo *timeInfo       ,
 
3743
                                      PaStreamCallbackFlags     statusFlags    ,
 
3744
                                      void                     *userData       )
 
3745
{
 
3746
    PaError result = paNoError; /* Initial return value. */
 
3747
    PaAsioStream *stream = *(PaAsioStream**)userData; /* The PA ASIO stream. */
 
3748
    PaAsioStreamBlockingState *blockingState = stream->blockingState; /* Persume blockingState is valid, otherwise the callback wouldn't be running. */
 
3749
 
 
3750
    /* Get a pointer to the stream's blocking i/o buffer processor. */
 
3751
    PaUtilBufferProcessor *pBp = &blockingState->bufferProcessor;
 
3752
    PaUtilRingBuffer      *pRb = NULL;
 
3753
 
 
3754
    /* If output data has been requested. */
 
3755
    if( stream->outputChannelCount )
 
3756
    {
 
3757
        /* If the callback input argument signalizes a output underflow,
 
3758
           make sure the WriteStream() function knows about it, too! */
 
3759
        if( statusFlags & paOutputUnderflowed ) {
 
3760
            blockingState->outputUnderflowFlag = TRUE;
 
3761
        }
 
3762
 
 
3763
        /* Access the corresponding ring buffer. */
 
3764
        pRb = &blockingState->writeRingBuffer;
 
3765
 
 
3766
        /* If the blocking i/o buffer contains enough output data, */
 
3767
        if( PaUtil_GetRingBufferReadAvailable(pRb) >= (long) framesPerBuffer )
 
3768
        {
 
3769
            /* Extract the requested data from the ring buffer. */
 
3770
            PaUtil_ReadRingBuffer( pRb, outputBuffer, framesPerBuffer );
 
3771
        }
 
3772
        else /* If no output data is available :-( */
 
3773
        {
 
3774
            /* Signalize a write-buffer underflow. */
 
3775
            blockingState->outputUnderflowFlag = TRUE;
 
3776
 
 
3777
            /* Fill the output buffer with silence. */
 
3778
            (*pBp->outputZeroer)( outputBuffer, 1, pBp->outputChannelCount * framesPerBuffer );
 
3779
 
 
3780
            /* If playback is to be stopped */
 
3781
            if( blockingState->stopFlag && PaUtil_GetRingBufferReadAvailable(pRb) < (long) framesPerBuffer )
 
3782
            {
 
3783
                /* Extract all the remaining data from the ring buffer,
 
3784
                   whether it is a complete data block or not. */
 
3785
                PaUtil_ReadRingBuffer( pRb, outputBuffer, PaUtil_GetRingBufferReadAvailable(pRb) );
 
3786
            }
 
3787
        }
 
3788
 
 
3789
        /* Set blocking i/o event? */
 
3790
        if( blockingState->writeBuffersRequestedFlag && PaUtil_GetRingBufferWriteAvailable(pRb) >= (long) blockingState->writeBuffersRequested )
 
3791
        {
 
3792
            /* Reset buffer request. */
 
3793
            blockingState->writeBuffersRequestedFlag = FALSE;
 
3794
            blockingState->writeBuffersRequested     = 0;
 
3795
            /* Signalize that requested buffers are ready. */
 
3796
            SetEvent( blockingState->writeBuffersReadyEvent );
 
3797
            /* What do we do if SetEvent() returns zero, i.e. the event
 
3798
               could not be set? How to return errors from within the
 
3799
               callback? - S.Fischer */
 
3800
        }
 
3801
    }
 
3802
 
 
3803
    /* If input data has been supplied. */
 
3804
    if( stream->inputChannelCount )
 
3805
    {
 
3806
        /* If the callback input argument signalizes a input overflow,
 
3807
           make sure the ReadStream() function knows about it, too! */
 
3808
        if( statusFlags & paInputOverflowed ) {
 
3809
            blockingState->inputOverflowFlag = TRUE;
 
3810
        }
 
3811
 
 
3812
        /* Access the corresponding ring buffer. */
 
3813
        pRb = &blockingState->readRingBuffer;
 
3814
 
 
3815
        /* If the blocking i/o buffer contains not enough input buffers */
 
3816
        if( PaUtil_GetRingBufferWriteAvailable(pRb) < (long) framesPerBuffer )
 
3817
        {
 
3818
            /* Signalize a read-buffer overflow. */
 
3819
            blockingState->inputOverflowFlag = TRUE;
 
3820
 
 
3821
            /* Remove some old data frames from the buffer. */
 
3822
            PaUtil_AdvanceRingBufferReadIndex( pRb, framesPerBuffer );
 
3823
        }
 
3824
 
 
3825
        /* Insert the current input data into the ring buffer. */
 
3826
        PaUtil_WriteRingBuffer( pRb, inputBuffer, framesPerBuffer );
 
3827
 
 
3828
        /* Set blocking i/o event? */
 
3829
        if( blockingState->readFramesRequestedFlag && PaUtil_GetRingBufferReadAvailable(pRb) >= (long) blockingState->readFramesRequested )
 
3830
        {
 
3831
            /* Reset buffer request. */
 
3832
            blockingState->readFramesRequestedFlag = FALSE;
 
3833
            blockingState->readFramesRequested     = 0;
 
3834
            /* Signalize that requested buffers are ready. */
 
3835
            SetEvent( blockingState->readFramesReadyEvent );
 
3836
            /* What do we do if SetEvent() returns zero, i.e. the event
 
3837
               could not be set? How to return errors from within the
 
3838
               callback? - S.Fischer */
 
3839
            /** @todo report an error with PA_DEBUG */
 
3840
        }
 
3841
    }
 
3842
 
 
3843
    return paContinue;
 
3844
}
 
3845
 
 
3846
 
 
3847
PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific )
 
3848
{
 
3849
    PaError result = paNoError;
 
3850
    PaUtilHostApiRepresentation *hostApi;
 
3851
    PaDeviceIndex hostApiDevice;
 
3852
    ASIODriverInfo asioDriverInfo;
 
3853
    ASIOError asioError;
 
3854
    int asioIsInitialized = 0;
 
3855
    PaAsioHostApiRepresentation *asioHostApi;
 
3856
    PaAsioDeviceInfo *asioDeviceInfo;
 
3857
 
 
3858
 
 
3859
    result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
 
3860
    if( result != paNoError )
 
3861
        goto error;
 
3862
 
 
3863
    result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
 
3864
    if( result != paNoError )
 
3865
        goto error;
 
3866
 
 
3867
    /*
 
3868
        In theory we could proceed if the currently open device was the same
 
3869
        one for which the control panel was requested, however  because the
 
3870
        window pointer is not available until this function is called we
 
3871
        currently need to call ASIOInit() again here, which of course can't be
 
3872
        done safely while a stream is open.
 
3873
    */
 
3874
 
 
3875
    asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
 
3876
    if( asioHostApi->openAsioDeviceIndex != paNoDevice )
 
3877
    {
 
3878
        result = paDeviceUnavailable;
 
3879
        goto error;
 
3880
    }
 
3881
 
 
3882
    asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
 
3883
 
 
3884
    /* See notes about CoInitialize(0) in LoadAsioDriver(). */
 
3885
        CoInitialize(0);
 
3886
 
 
3887
    if( !asioHostApi->asioDrivers->loadDriver( const_cast<char*>(asioDeviceInfo->commonDeviceInfo.name) ) )
 
3888
    {
 
3889
        result = paUnanticipatedHostError;
 
3890
        goto error;
 
3891
    }
 
3892
 
 
3893
    /* CRUCIAL!!! */
 
3894
    memset( &asioDriverInfo, 0, sizeof(ASIODriverInfo) );
 
3895
    asioDriverInfo.asioVersion = 2;
 
3896
    asioDriverInfo.sysRef = systemSpecific;
 
3897
    asioError = ASIOInit( &asioDriverInfo );
 
3898
    if( asioError != ASE_OK )
 
3899
    {
 
3900
        result = paUnanticipatedHostError;
 
3901
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
 
3902
        goto error;
 
3903
    }
 
3904
    else
 
3905
    {
 
3906
        asioIsInitialized = 1;
 
3907
    }
 
3908
 
 
3909
PA_DEBUG(("PaAsio_ShowControlPanel: ASIOInit(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
 
3910
PA_DEBUG(("asioVersion: ASIOInit(): %ld\n",   asioDriverInfo.asioVersion )); 
 
3911
PA_DEBUG(("driverVersion: ASIOInit(): %ld\n", asioDriverInfo.driverVersion )); 
 
3912
PA_DEBUG(("Name: ASIOInit(): %s\n",           asioDriverInfo.name )); 
 
3913
PA_DEBUG(("ErrorMessage: ASIOInit(): %s\n",   asioDriverInfo.errorMessage )); 
 
3914
 
 
3915
    asioError = ASIOControlPanel();
 
3916
    if( asioError != ASE_OK )
 
3917
    {
 
3918
        PA_DEBUG(("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
 
3919
        result = paUnanticipatedHostError;
 
3920
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
 
3921
        goto error;
 
3922
    }
 
3923
 
 
3924
PA_DEBUG(("PaAsio_ShowControlPanel: ASIOControlPanel(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
 
3925
 
 
3926
    asioError = ASIOExit();
 
3927
    if( asioError != ASE_OK )
 
3928
    {
 
3929
        result = paUnanticipatedHostError;
 
3930
        PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
 
3931
        asioIsInitialized = 0;
 
3932
        goto error;
 
3933
    }
 
3934
 
 
3935
        CoUninitialize();
 
3936
PA_DEBUG(("PaAsio_ShowControlPanel: ASIOExit(): %s\n", PaAsio_GetAsioErrorText(asioError) ));
 
3937
 
 
3938
    return result;
 
3939
 
 
3940
error:
 
3941
    if( asioIsInitialized )
 
3942
        {
 
3943
                ASIOExit();
 
3944
        }
 
3945
        CoUninitialize();
 
3946
 
 
3947
    return result;
 
3948
}
 
3949
 
 
3950
 
 
3951
PaError PaAsio_GetInputChannelName( PaDeviceIndex device, int channelIndex,
 
3952
        const char** channelName )
 
3953
{
 
3954
    PaError result = paNoError;
 
3955
    PaUtilHostApiRepresentation *hostApi;
 
3956
    PaDeviceIndex hostApiDevice;
 
3957
    PaAsioDeviceInfo *asioDeviceInfo;
 
3958
 
 
3959
 
 
3960
    result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
 
3961
    if( result != paNoError )
 
3962
        goto error;
 
3963
 
 
3964
    result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
 
3965
    if( result != paNoError )
 
3966
        goto error;
 
3967
 
 
3968
    asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
 
3969
 
 
3970
    if( channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxInputChannels ){
 
3971
        result = paInvalidChannelCount;
 
3972
        goto error;
 
3973
    }
 
3974
 
 
3975
    *channelName = asioDeviceInfo->asioChannelInfos[channelIndex].name;
 
3976
 
 
3977
    return paNoError;
 
3978
    
 
3979
error:
 
3980
    return result;
 
3981
}
 
3982
 
 
3983
 
 
3984
PaError PaAsio_GetOutputChannelName( PaDeviceIndex device, int channelIndex,
 
3985
        const char** channelName )
 
3986
{
 
3987
    PaError result = paNoError;
 
3988
    PaUtilHostApiRepresentation *hostApi;
 
3989
    PaDeviceIndex hostApiDevice;
 
3990
    PaAsioDeviceInfo *asioDeviceInfo;
 
3991
 
 
3992
 
 
3993
    result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
 
3994
    if( result != paNoError )
 
3995
        goto error;
 
3996
 
 
3997
    result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
 
3998
    if( result != paNoError )
 
3999
        goto error;
 
4000
 
 
4001
    asioDeviceInfo = (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
 
4002
 
 
4003
    if( channelIndex < 0 || channelIndex >= asioDeviceInfo->commonDeviceInfo.maxOutputChannels ){
 
4004
        result = paInvalidChannelCount;
 
4005
        goto error;
 
4006
    }
 
4007
 
 
4008
    *channelName = asioDeviceInfo->asioChannelInfos[
 
4009
            asioDeviceInfo->commonDeviceInfo.maxInputChannels + channelIndex].name;
 
4010
 
 
4011
    return paNoError;
 
4012
    
 
4013
error:
 
4014
    return result;
 
4015
}
 
4016
 
 
4017
 
 
4018
/* NOTE: the following functions are ASIO-stream specific, and are called directly
 
4019
    by client code. We need to check for many more error conditions here because
 
4020
    we don't have the benefit of pa_front.c's parameter checking.
 
4021
*/
 
4022
 
 
4023
static PaError GetAsioStreamPointer( PaAsioStream **stream, PaStream *s )
 
4024
{
 
4025
    PaError result;
 
4026
    PaUtilHostApiRepresentation *hostApi;
 
4027
    PaAsioHostApiRepresentation *asioHostApi;
 
4028
    
 
4029
    result = PaUtil_ValidateStreamPointer( s );
 
4030
    if( result != paNoError )
 
4031
        return result;
 
4032
 
 
4033
    result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
 
4034
    if( result != paNoError )
 
4035
        return result;
 
4036
 
 
4037
    asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
 
4038
    
 
4039
    if( PA_STREAM_REP( s )->streamInterface == &asioHostApi->callbackStreamInterface
 
4040
            || PA_STREAM_REP( s )->streamInterface == &asioHostApi->blockingStreamInterface )
 
4041
    {
 
4042
        /* s is an ASIO  stream */
 
4043
        *stream = (PaAsioStream *)s;
 
4044
        return paNoError;
 
4045
    }
 
4046
    else
 
4047
    {
 
4048
        return paIncompatibleStreamHostApi;
 
4049
    }
 
4050
}
 
4051
 
 
4052
 
 
4053
PaError PaAsio_SetStreamSampleRate( PaStream* s, double sampleRate )
 
4054
{
 
4055
    PaAsioStream *stream;
 
4056
    PaError result = GetAsioStreamPointer( &stream, s );
 
4057
    if( result != paNoError )
 
4058
        return result;
 
4059
 
 
4060
    if( stream != theAsioStream )
 
4061
        return paBadStreamPtr;
 
4062
 
 
4063
    return ValidateAndSetSampleRate( sampleRate );
 
4064
}
 
4065