2
* $Id: pa_skeleton.c 1097 2006-08-26 08:27:53Z rossb $
3
* Portable Audio I/O Library skeleton implementation
4
* demonstrates how to use the common functions to implement support
7
* Based on the Open Source API proposed by Ross Bencina
8
* Copyright (c) 1999-2002 Ross Bencina, Phil Burk
10
* Permission is hereby granted, free of charge, to any person obtaining
11
* a copy of this software and associated documentation files
12
* (the "Software"), to deal in the Software without restriction,
13
* including without limitation the rights to use, copy, modify, merge,
14
* publish, distribute, sublicense, and/or sell copies of the Software,
15
* and to permit persons to whom the Software is furnished to do so,
16
* subject to the following conditions:
18
* The above copyright notice and this permission notice shall be
19
* included in all copies or substantial portions of the Software.
21
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
25
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
26
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
* The text above constitutes the entire PortAudio license; however,
32
* the PortAudio community also makes the following non-binding requests:
34
* Any person wishing to distribute modifications to the Software is
35
* requested to send the modifications to the original developer so that
36
* they can be incorporated into the canonical version. It is also
37
* requested that these non-binding requests be included along with the
44
@brief Skeleton implementation of support for a host API.
46
@note This file is provided as a starting point for implementing support for
47
a new host API. IMPLEMENT ME comments are used to indicate functionality
48
which much be customised for each implementation.
52
#include <string.h> /* strlen() */
55
#include "pa_allocation.h"
56
#include "pa_hostapi.h"
57
#include "pa_stream.h"
58
#include "pa_cpuload.h"
59
#include "pa_process.h"
62
/* prototypes for functions declared in this file */
67
#endif /* __cplusplus */
69
PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
73
#endif /* __cplusplus */
76
static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
77
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
78
const PaStreamParameters *inputParameters,
79
const PaStreamParameters *outputParameters,
81
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
83
const PaStreamParameters *inputParameters,
84
const PaStreamParameters *outputParameters,
86
unsigned long framesPerBuffer,
87
PaStreamFlags streamFlags,
88
PaStreamCallback *streamCallback,
90
static PaError CloseStream( PaStream* stream );
91
static PaError StartStream( PaStream *stream );
92
static PaError StopStream( PaStream *stream );
93
static PaError AbortStream( PaStream *stream );
94
static PaError IsStreamStopped( PaStream *s );
95
static PaError IsStreamActive( PaStream *stream );
96
static PaTime GetStreamTime( PaStream *stream );
97
static double GetStreamCpuLoad( PaStream* stream );
98
static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
99
static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
100
static signed long GetStreamReadAvailable( PaStream* stream );
101
static signed long GetStreamWriteAvailable( PaStream* stream );
104
/* IMPLEMENT ME: a macro like the following one should be used for reporting
106
#define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \
107
PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )
109
/* PaSkeletonHostApiRepresentation - host api datastructure specific to this implementation */
113
PaUtilHostApiRepresentation inheritedHostApiRep;
114
PaUtilStreamInterface callbackStreamInterface;
115
PaUtilStreamInterface blockingStreamInterface;
117
PaUtilAllocationGroup *allocations;
119
/* implementation specific data goes here */
121
PaSkeletonHostApiRepresentation; /* IMPLEMENT ME: rename this */
124
PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
126
PaError result = paNoError;
128
PaSkeletonHostApiRepresentation *skeletonHostApi;
129
PaDeviceInfo *deviceInfoArray;
131
skeletonHostApi = (PaSkeletonHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaSkeletonHostApiRepresentation) );
132
if( !skeletonHostApi )
134
result = paInsufficientMemory;
138
skeletonHostApi->allocations = PaUtil_CreateAllocationGroup();
139
if( !skeletonHostApi->allocations )
141
result = paInsufficientMemory;
145
*hostApi = &skeletonHostApi->inheritedHostApiRep;
146
(*hostApi)->info.structVersion = 1;
147
(*hostApi)->info.type = paInDevelopment; /* IMPLEMENT ME: change to correct type id */
148
(*hostApi)->info.name = "skeleton implementation"; /* IMPLEMENT ME: change to correct name */
150
(*hostApi)->info.defaultInputDevice = paNoDevice; /* IMPLEMENT ME */
151
(*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */
153
(*hostApi)->info.deviceCount = 0;
155
deviceCount = 0; /* IMPLEMENT ME */
157
if( deviceCount > 0 )
159
(*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
160
skeletonHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
161
if( !(*hostApi)->deviceInfos )
163
result = paInsufficientMemory;
167
/* allocate all device info structs in a contiguous block */
168
deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
169
skeletonHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount );
170
if( !deviceInfoArray )
172
result = paInsufficientMemory;
176
for( i=0; i < deviceCount; ++i )
178
PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
179
deviceInfo->structVersion = 2;
180
deviceInfo->hostApi = hostApiIndex;
181
deviceInfo->name = 0; /* IMPLEMENT ME: allocate block and copy name eg:
182
deviceName = (char*)PaUtil_GroupAllocateMemory( skeletonHostApi->allocations, strlen(srcName) + 1 );
185
result = paInsufficientMemory;
188
strcpy( deviceName, srcName );
189
deviceInfo->name = deviceName;
192
deviceInfo->maxInputChannels = 0; /* IMPLEMENT ME */
193
deviceInfo->maxOutputChannels = 0; /* IMPLEMENT ME */
195
deviceInfo->defaultLowInputLatency = 0.; /* IMPLEMENT ME */
196
deviceInfo->defaultLowOutputLatency = 0.; /* IMPLEMENT ME */
197
deviceInfo->defaultHighInputLatency = 0.; /* IMPLEMENT ME */
198
deviceInfo->defaultHighOutputLatency = 0.; /* IMPLEMENT ME */
200
deviceInfo->defaultSampleRate = 0.; /* IMPLEMENT ME */
202
(*hostApi)->deviceInfos[i] = deviceInfo;
203
++(*hostApi)->info.deviceCount;
207
(*hostApi)->Terminate = Terminate;
208
(*hostApi)->OpenStream = OpenStream;
209
(*hostApi)->IsFormatSupported = IsFormatSupported;
211
PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, CloseStream, StartStream,
212
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
213
GetStreamTime, GetStreamCpuLoad,
214
PaUtil_DummyRead, PaUtil_DummyWrite,
215
PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
217
PaUtil_InitializeStreamInterface( &skeletonHostApi->blockingStreamInterface, CloseStream, StartStream,
218
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
219
GetStreamTime, PaUtil_DummyGetCpuLoad,
220
ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
225
if( skeletonHostApi )
227
if( skeletonHostApi->allocations )
229
PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
230
PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
233
PaUtil_FreeMemory( skeletonHostApi );
239
static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
241
PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;
245
- clean up any resources not handled by the allocation group
248
if( skeletonHostApi->allocations )
250
PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
251
PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
254
PaUtil_FreeMemory( skeletonHostApi );
258
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
259
const PaStreamParameters *inputParameters,
260
const PaStreamParameters *outputParameters,
263
int inputChannelCount, outputChannelCount;
264
PaSampleFormat inputSampleFormat, outputSampleFormat;
266
if( inputParameters )
268
inputChannelCount = inputParameters->channelCount;
269
inputSampleFormat = inputParameters->sampleFormat;
271
/* all standard sample formats are supported by the buffer adapter,
272
this implementation doesn't support any custom sample formats */
273
if( inputSampleFormat & paCustomFormat )
274
return paSampleFormatNotSupported;
276
/* unless alternate device specification is supported, reject the use of
277
paUseHostApiSpecificDeviceSpecification */
279
if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
280
return paInvalidDevice;
282
/* check that input device can support inputChannelCount */
283
if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
284
return paInvalidChannelCount;
286
/* validate inputStreamInfo */
287
if( inputParameters->hostApiSpecificStreamInfo )
288
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
292
inputChannelCount = 0;
295
if( outputParameters )
297
outputChannelCount = outputParameters->channelCount;
298
outputSampleFormat = outputParameters->sampleFormat;
300
/* all standard sample formats are supported by the buffer adapter,
301
this implementation doesn't support any custom sample formats */
302
if( outputSampleFormat & paCustomFormat )
303
return paSampleFormatNotSupported;
305
/* unless alternate device specification is supported, reject the use of
306
paUseHostApiSpecificDeviceSpecification */
308
if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
309
return paInvalidDevice;
311
/* check that output device can support outputChannelCount */
312
if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
313
return paInvalidChannelCount;
315
/* validate outputStreamInfo */
316
if( outputParameters->hostApiSpecificStreamInfo )
317
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
321
outputChannelCount = 0;
327
- if a full duplex stream is requested, check that the combination
328
of input and output parameters is supported if necessary
330
- check that the device supports sampleRate
332
Because the buffer adapter handles conversion between all standard
333
sample formats, the following checks are only required if paCustomFormat
334
is implemented, or under some other unusual conditions.
336
- check that input device can support inputSampleFormat, or that
337
we have the capability to convert from inputSampleFormat to
340
- check that output device can support outputSampleFormat, or that
341
we have the capability to convert from outputSampleFormat to
346
/* suppress unused variable warnings */
349
return paFormatIsSupported;
352
/* PaSkeletonStream - a stream data structure specifically for this implementation */
354
typedef struct PaSkeletonStream
355
{ /* IMPLEMENT ME: rename this */
356
PaUtilStreamRepresentation streamRepresentation;
357
PaUtilCpuLoadMeasurer cpuLoadMeasurer;
358
PaUtilBufferProcessor bufferProcessor;
361
- implementation specific data goes here
363
unsigned long framesPerHostCallback; /* just an example */
367
/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
369
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
371
const PaStreamParameters *inputParameters,
372
const PaStreamParameters *outputParameters,
374
unsigned long framesPerBuffer,
375
PaStreamFlags streamFlags,
376
PaStreamCallback *streamCallback,
379
PaError result = paNoError;
380
PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;
381
PaSkeletonStream *stream = 0;
382
unsigned long framesPerHostBuffer = framesPerBuffer; /* these may not be equivalent for all implementations */
383
int inputChannelCount, outputChannelCount;
384
PaSampleFormat inputSampleFormat, outputSampleFormat;
385
PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
388
if( inputParameters )
390
inputChannelCount = inputParameters->channelCount;
391
inputSampleFormat = inputParameters->sampleFormat;
393
/* unless alternate device specification is supported, reject the use of
394
paUseHostApiSpecificDeviceSpecification */
396
if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
397
return paInvalidDevice;
399
/* check that input device can support inputChannelCount */
400
if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
401
return paInvalidChannelCount;
403
/* validate inputStreamInfo */
404
if( inputParameters->hostApiSpecificStreamInfo )
405
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
407
/* IMPLEMENT ME - establish which host formats are available */
408
hostInputSampleFormat =
409
PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat );
413
inputChannelCount = 0;
414
inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */
417
if( outputParameters )
419
outputChannelCount = outputParameters->channelCount;
420
outputSampleFormat = outputParameters->sampleFormat;
422
/* unless alternate device specification is supported, reject the use of
423
paUseHostApiSpecificDeviceSpecification */
425
if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
426
return paInvalidDevice;
428
/* check that output device can support inputChannelCount */
429
if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
430
return paInvalidChannelCount;
432
/* validate outputStreamInfo */
433
if( outputParameters->hostApiSpecificStreamInfo )
434
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
436
/* IMPLEMENT ME - establish which host formats are available */
437
hostOutputSampleFormat =
438
PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat );
442
outputChannelCount = 0;
443
outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */
449
( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? )
451
- check that input device can support inputSampleFormat, or that
452
we have the capability to convert from outputSampleFormat to
455
- check that output device can support outputSampleFormat, or that
456
we have the capability to convert from outputSampleFormat to
459
- if a full duplex stream is requested, check that the combination
460
of input and output parameters is supported
462
- check that the device supports sampleRate
464
- alter sampleRate to a close allowable rate if possible / necessary
466
- validate suggestedInputLatency and suggestedOutputLatency parameters,
467
use default values where necessary
473
/* validate platform specific flags */
474
if( (streamFlags & paPlatformSpecificFlags) != 0 )
475
return paInvalidFlag; /* unexpected platform specific flag */
478
stream = (PaSkeletonStream*)PaUtil_AllocateMemory( sizeof(PaSkeletonStream) );
481
result = paInsufficientMemory;
487
PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
488
&skeletonHostApi->callbackStreamInterface, streamCallback, userData );
492
PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
493
&skeletonHostApi->blockingStreamInterface, streamCallback, userData );
496
PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
499
/* we assume a fixed host buffer size in this example, but the buffer processor
500
can also support bounded and unknown host buffer sizes by passing
501
paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of
502
paUtilFixedHostBufferSize below. */
504
result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
505
inputChannelCount, inputSampleFormat, hostInputSampleFormat,
506
outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
507
sampleRate, streamFlags, framesPerBuffer,
508
framesPerHostBuffer, paUtilFixedHostBufferSize,
509
streamCallback, userData );
510
if( result != paNoError )
515
IMPLEMENT ME: initialise the following fields with estimated or actual
518
stream->streamRepresentation.streamInfo.inputLatency =
519
PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor);
520
stream->streamRepresentation.streamInfo.outputLatency =
521
PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor);
522
stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
527
- additional stream setup + opening
530
stream->framesPerHostCallback = framesPerHostBuffer;
532
*s = (PaStream*)stream;
538
PaUtil_FreeMemory( stream );
544
ExampleHostProcessingLoop() illustrates the kind of processing which may
545
occur in a host implementation.
548
static void ExampleHostProcessingLoop( void *inputBuffer, void *outputBuffer, void *userData )
550
PaSkeletonStream *stream = (PaSkeletonStream*)userData;
551
PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */
553
unsigned long framesProcessed;
555
PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
559
- generate timing information
560
- handle buffer slips
564
If you need to byte swap or shift inputBuffer to convert it into a
565
portaudio format, do it here.
570
PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */ );
573
depending on whether the host buffers are interleaved, non-interleaved
574
or a mixture, you will want to call PaUtil_SetInterleaved*Channels(),
575
PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here.
578
PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
579
PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor,
580
0, /* first channel of inputBuffer is channel 0 */
582
0 ); /* 0 - use inputChannelCount passed to init buffer processor */
584
PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
585
PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor,
586
0, /* first channel of outputBuffer is channel 0 */
588
0 ); /* 0 - use outputChannelCount passed to init buffer processor */
590
/* you must pass a valid value of callback result to PaUtil_EndBufferProcessing()
591
in general you would pass paContinue for normal operation, and
592
paComplete to drain the buffer processor's internal output buffer.
593
You can check whether the buffer processor's output buffer is empty
594
using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor )
596
callbackResult = paContinue;
597
framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
601
If you need to byte swap or shift outputBuffer to convert it to
602
host format, do it here.
605
PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
608
if( callbackResult == paContinue )
610
/* nothing special to do */
612
else if( callbackResult == paAbort )
614
/* IMPLEMENT ME - finish playback immediately */
616
/* once finished, call the finished callback */
617
if( stream->streamRepresentation.streamFinishedCallback != 0 )
618
stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
622
/* User callback has asked us to stop with paComplete or other non-zero value */
624
/* IMPLEMENT ME - finish playback once currently queued audio has completed */
626
/* once finished, call the finished callback */
627
if( stream->streamRepresentation.streamFinishedCallback != 0 )
628
stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
634
When CloseStream() is called, the multi-api layer ensures that
635
the stream has already been stopped or aborted.
637
static PaError CloseStream( PaStream* s )
639
PaError result = paNoError;
640
PaSkeletonStream *stream = (PaSkeletonStream*)s;
644
- additional stream closing + cleanup
647
PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
648
PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
649
PaUtil_FreeMemory( stream );
655
static PaError StartStream( PaStream *s )
657
PaError result = paNoError;
658
PaSkeletonStream *stream = (PaSkeletonStream*)s;
660
PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
662
/* IMPLEMENT ME, see portaudio.h for required behavior */
664
/* suppress unused function warning. the code in ExampleHostProcessingLoop or
665
something similar should be implemented to feed samples to and from the
666
host after StartStream() is called.
668
(void) ExampleHostProcessingLoop;
674
static PaError StopStream( PaStream *s )
676
PaError result = paNoError;
677
PaSkeletonStream *stream = (PaSkeletonStream*)s;
679
/* suppress unused variable warnings */
682
/* IMPLEMENT ME, see portaudio.h for required behavior */
688
static PaError AbortStream( PaStream *s )
690
PaError result = paNoError;
691
PaSkeletonStream *stream = (PaSkeletonStream*)s;
693
/* suppress unused variable warnings */
696
/* IMPLEMENT ME, see portaudio.h for required behavior */
702
static PaError IsStreamStopped( PaStream *s )
704
PaSkeletonStream *stream = (PaSkeletonStream*)s;
706
/* suppress unused variable warnings */
709
/* IMPLEMENT ME, see portaudio.h for required behavior */
715
static PaError IsStreamActive( PaStream *s )
717
PaSkeletonStream *stream = (PaSkeletonStream*)s;
719
/* suppress unused variable warnings */
722
/* IMPLEMENT ME, see portaudio.h for required behavior */
728
static PaTime GetStreamTime( PaStream *s )
730
PaSkeletonStream *stream = (PaSkeletonStream*)s;
732
/* suppress unused variable warnings */
735
/* IMPLEMENT ME, see portaudio.h for required behavior*/
741
static double GetStreamCpuLoad( PaStream* s )
743
PaSkeletonStream *stream = (PaSkeletonStream*)s;
745
return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
750
As separate stream interfaces are used for blocking and callback
751
streams, the following functions can be guaranteed to only be called
752
for blocking streams.
755
static PaError ReadStream( PaStream* s,
757
unsigned long frames )
759
PaSkeletonStream *stream = (PaSkeletonStream*)s;
761
/* suppress unused variable warnings */
766
/* IMPLEMENT ME, see portaudio.h for required behavior*/
772
static PaError WriteStream( PaStream* s,
774
unsigned long frames )
776
PaSkeletonStream *stream = (PaSkeletonStream*)s;
778
/* suppress unused variable warnings */
783
/* IMPLEMENT ME, see portaudio.h for required behavior*/
789
static signed long GetStreamReadAvailable( PaStream* s )
791
PaSkeletonStream *stream = (PaSkeletonStream*)s;
793
/* suppress unused variable warnings */
796
/* IMPLEMENT ME, see portaudio.h for required behavior*/
802
static signed long GetStreamWriteAvailable( PaStream* s )
804
PaSkeletonStream *stream = (PaSkeletonStream*)s;
806
/* suppress unused variable warnings */
809
/* IMPLEMENT ME, see portaudio.h for required behavior*/