2
* $Id: pa_skeleton.c 1339 2008-02-15 07:50:33Z 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
This file is provided as a starting point for implementing support for
47
a new host API. It provides examples of how the common code can be used.
49
@note IMPLEMENT ME comments are used to indicate functionality
50
which much be customised for each implementation.
54
#include <string.h> /* strlen() */
57
#include "pa_allocation.h"
58
#include "pa_hostapi.h"
59
#include "pa_stream.h"
60
#include "pa_cpuload.h"
61
#include "pa_process.h"
64
/* prototypes for functions declared in this file */
69
#endif /* __cplusplus */
71
PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
75
#endif /* __cplusplus */
78
static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
79
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
80
const PaStreamParameters *inputParameters,
81
const PaStreamParameters *outputParameters,
83
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
85
const PaStreamParameters *inputParameters,
86
const PaStreamParameters *outputParameters,
88
unsigned long framesPerBuffer,
89
PaStreamFlags streamFlags,
90
PaStreamCallback *streamCallback,
92
static PaError CloseStream( PaStream* stream );
93
static PaError StartStream( PaStream *stream );
94
static PaError StopStream( PaStream *stream );
95
static PaError AbortStream( PaStream *stream );
96
static PaError IsStreamStopped( PaStream *s );
97
static PaError IsStreamActive( PaStream *stream );
98
static PaTime GetStreamTime( PaStream *stream );
99
static double GetStreamCpuLoad( PaStream* stream );
100
static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
101
static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
102
static signed long GetStreamReadAvailable( PaStream* stream );
103
static signed long GetStreamWriteAvailable( PaStream* stream );
106
/* IMPLEMENT ME: a macro like the following one should be used for reporting
108
#define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \
109
PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )
111
/* PaSkeletonHostApiRepresentation - host api datastructure specific to this implementation */
115
PaUtilHostApiRepresentation inheritedHostApiRep;
116
PaUtilStreamInterface callbackStreamInterface;
117
PaUtilStreamInterface blockingStreamInterface;
119
PaUtilAllocationGroup *allocations;
121
/* implementation specific data goes here */
123
PaSkeletonHostApiRepresentation; /* IMPLEMENT ME: rename this */
126
PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
128
PaError result = paNoError;
130
PaSkeletonHostApiRepresentation *skeletonHostApi;
131
PaDeviceInfo *deviceInfoArray;
133
skeletonHostApi = (PaSkeletonHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaSkeletonHostApiRepresentation) );
134
if( !skeletonHostApi )
136
result = paInsufficientMemory;
140
skeletonHostApi->allocations = PaUtil_CreateAllocationGroup();
141
if( !skeletonHostApi->allocations )
143
result = paInsufficientMemory;
147
*hostApi = &skeletonHostApi->inheritedHostApiRep;
148
(*hostApi)->info.structVersion = 1;
149
(*hostApi)->info.type = paInDevelopment; /* IMPLEMENT ME: change to correct type id */
150
(*hostApi)->info.name = "skeleton implementation"; /* IMPLEMENT ME: change to correct name */
152
(*hostApi)->info.defaultInputDevice = paNoDevice; /* IMPLEMENT ME */
153
(*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */
155
(*hostApi)->info.deviceCount = 0;
157
deviceCount = 0; /* IMPLEMENT ME */
159
if( deviceCount > 0 )
161
(*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
162
skeletonHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
163
if( !(*hostApi)->deviceInfos )
165
result = paInsufficientMemory;
169
/* allocate all device info structs in a contiguous block */
170
deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
171
skeletonHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount );
172
if( !deviceInfoArray )
174
result = paInsufficientMemory;
178
for( i=0; i < deviceCount; ++i )
180
PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
181
deviceInfo->structVersion = 2;
182
deviceInfo->hostApi = hostApiIndex;
183
deviceInfo->name = 0; /* IMPLEMENT ME: allocate block and copy name eg:
184
deviceName = (char*)PaUtil_GroupAllocateMemory( skeletonHostApi->allocations, strlen(srcName) + 1 );
187
result = paInsufficientMemory;
190
strcpy( deviceName, srcName );
191
deviceInfo->name = deviceName;
194
deviceInfo->maxInputChannels = 0; /* IMPLEMENT ME */
195
deviceInfo->maxOutputChannels = 0; /* IMPLEMENT ME */
197
deviceInfo->defaultLowInputLatency = 0.; /* IMPLEMENT ME */
198
deviceInfo->defaultLowOutputLatency = 0.; /* IMPLEMENT ME */
199
deviceInfo->defaultHighInputLatency = 0.; /* IMPLEMENT ME */
200
deviceInfo->defaultHighOutputLatency = 0.; /* IMPLEMENT ME */
202
deviceInfo->defaultSampleRate = 0.; /* IMPLEMENT ME */
204
(*hostApi)->deviceInfos[i] = deviceInfo;
205
++(*hostApi)->info.deviceCount;
209
(*hostApi)->Terminate = Terminate;
210
(*hostApi)->OpenStream = OpenStream;
211
(*hostApi)->IsFormatSupported = IsFormatSupported;
213
PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, CloseStream, StartStream,
214
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
215
GetStreamTime, GetStreamCpuLoad,
216
PaUtil_DummyRead, PaUtil_DummyWrite,
217
PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
219
PaUtil_InitializeStreamInterface( &skeletonHostApi->blockingStreamInterface, CloseStream, StartStream,
220
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
221
GetStreamTime, PaUtil_DummyGetCpuLoad,
222
ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
227
if( skeletonHostApi )
229
if( skeletonHostApi->allocations )
231
PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
232
PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
235
PaUtil_FreeMemory( skeletonHostApi );
241
static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
243
PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;
247
- clean up any resources not handled by the allocation group
250
if( skeletonHostApi->allocations )
252
PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
253
PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
256
PaUtil_FreeMemory( skeletonHostApi );
260
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
261
const PaStreamParameters *inputParameters,
262
const PaStreamParameters *outputParameters,
265
int inputChannelCount, outputChannelCount;
266
PaSampleFormat inputSampleFormat, outputSampleFormat;
268
if( inputParameters )
270
inputChannelCount = inputParameters->channelCount;
271
inputSampleFormat = inputParameters->sampleFormat;
273
/* all standard sample formats are supported by the buffer adapter,
274
this implementation doesn't support any custom sample formats */
275
if( inputSampleFormat & paCustomFormat )
276
return paSampleFormatNotSupported;
278
/* unless alternate device specification is supported, reject the use of
279
paUseHostApiSpecificDeviceSpecification */
281
if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
282
return paInvalidDevice;
284
/* check that input device can support inputChannelCount */
285
if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
286
return paInvalidChannelCount;
288
/* validate inputStreamInfo */
289
if( inputParameters->hostApiSpecificStreamInfo )
290
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
294
inputChannelCount = 0;
297
if( outputParameters )
299
outputChannelCount = outputParameters->channelCount;
300
outputSampleFormat = outputParameters->sampleFormat;
302
/* all standard sample formats are supported by the buffer adapter,
303
this implementation doesn't support any custom sample formats */
304
if( outputSampleFormat & paCustomFormat )
305
return paSampleFormatNotSupported;
307
/* unless alternate device specification is supported, reject the use of
308
paUseHostApiSpecificDeviceSpecification */
310
if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
311
return paInvalidDevice;
313
/* check that output device can support outputChannelCount */
314
if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
315
return paInvalidChannelCount;
317
/* validate outputStreamInfo */
318
if( outputParameters->hostApiSpecificStreamInfo )
319
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
323
outputChannelCount = 0;
329
- if a full duplex stream is requested, check that the combination
330
of input and output parameters is supported if necessary
332
- check that the device supports sampleRate
334
Because the buffer adapter handles conversion between all standard
335
sample formats, the following checks are only required if paCustomFormat
336
is implemented, or under some other unusual conditions.
338
- check that input device can support inputSampleFormat, or that
339
we have the capability to convert from inputSampleFormat to
342
- check that output device can support outputSampleFormat, or that
343
we have the capability to convert from outputSampleFormat to
348
/* suppress unused variable warnings */
351
return paFormatIsSupported;
354
/* PaSkeletonStream - a stream data structure specifically for this implementation */
356
typedef struct PaSkeletonStream
357
{ /* IMPLEMENT ME: rename this */
358
PaUtilStreamRepresentation streamRepresentation;
359
PaUtilCpuLoadMeasurer cpuLoadMeasurer;
360
PaUtilBufferProcessor bufferProcessor;
363
- implementation specific data goes here
365
unsigned long framesPerHostCallback; /* just an example */
369
/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
371
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
373
const PaStreamParameters *inputParameters,
374
const PaStreamParameters *outputParameters,
376
unsigned long framesPerBuffer,
377
PaStreamFlags streamFlags,
378
PaStreamCallback *streamCallback,
381
PaError result = paNoError;
382
PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;
383
PaSkeletonStream *stream = 0;
384
unsigned long framesPerHostBuffer = framesPerBuffer; /* these may not be equivalent for all implementations */
385
int inputChannelCount, outputChannelCount;
386
PaSampleFormat inputSampleFormat, outputSampleFormat;
387
PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
390
if( inputParameters )
392
inputChannelCount = inputParameters->channelCount;
393
inputSampleFormat = inputParameters->sampleFormat;
395
/* unless alternate device specification is supported, reject the use of
396
paUseHostApiSpecificDeviceSpecification */
398
if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
399
return paInvalidDevice;
401
/* check that input device can support inputChannelCount */
402
if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
403
return paInvalidChannelCount;
405
/* validate inputStreamInfo */
406
if( inputParameters->hostApiSpecificStreamInfo )
407
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
409
/* IMPLEMENT ME - establish which host formats are available */
410
hostInputSampleFormat =
411
PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat );
415
inputChannelCount = 0;
416
inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */
419
if( outputParameters )
421
outputChannelCount = outputParameters->channelCount;
422
outputSampleFormat = outputParameters->sampleFormat;
424
/* unless alternate device specification is supported, reject the use of
425
paUseHostApiSpecificDeviceSpecification */
427
if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
428
return paInvalidDevice;
430
/* check that output device can support inputChannelCount */
431
if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
432
return paInvalidChannelCount;
434
/* validate outputStreamInfo */
435
if( outputParameters->hostApiSpecificStreamInfo )
436
return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
438
/* IMPLEMENT ME - establish which host formats are available */
439
hostOutputSampleFormat =
440
PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat );
444
outputChannelCount = 0;
445
outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */
451
( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? )
453
- check that input device can support inputSampleFormat, or that
454
we have the capability to convert from outputSampleFormat to
457
- check that output device can support outputSampleFormat, or that
458
we have the capability to convert from outputSampleFormat to
461
- if a full duplex stream is requested, check that the combination
462
of input and output parameters is supported
464
- check that the device supports sampleRate
466
- alter sampleRate to a close allowable rate if possible / necessary
468
- validate suggestedInputLatency and suggestedOutputLatency parameters,
469
use default values where necessary
475
/* validate platform specific flags */
476
if( (streamFlags & paPlatformSpecificFlags) != 0 )
477
return paInvalidFlag; /* unexpected platform specific flag */
480
stream = (PaSkeletonStream*)PaUtil_AllocateMemory( sizeof(PaSkeletonStream) );
483
result = paInsufficientMemory;
489
PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
490
&skeletonHostApi->callbackStreamInterface, streamCallback, userData );
494
PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
495
&skeletonHostApi->blockingStreamInterface, streamCallback, userData );
498
PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
501
/* we assume a fixed host buffer size in this example, but the buffer processor
502
can also support bounded and unknown host buffer sizes by passing
503
paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of
504
paUtilFixedHostBufferSize below. */
506
result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
507
inputChannelCount, inputSampleFormat, hostInputSampleFormat,
508
outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
509
sampleRate, streamFlags, framesPerBuffer,
510
framesPerHostBuffer, paUtilFixedHostBufferSize,
511
streamCallback, userData );
512
if( result != paNoError )
517
IMPLEMENT ME: initialise the following fields with estimated or actual
520
stream->streamRepresentation.streamInfo.inputLatency =
521
PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor);
522
stream->streamRepresentation.streamInfo.outputLatency =
523
PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor);
524
stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
529
- additional stream setup + opening
532
stream->framesPerHostCallback = framesPerHostBuffer;
534
*s = (PaStream*)stream;
540
PaUtil_FreeMemory( stream );
546
ExampleHostProcessingLoop() illustrates the kind of processing which may
547
occur in a host implementation.
550
static void ExampleHostProcessingLoop( void *inputBuffer, void *outputBuffer, void *userData )
552
PaSkeletonStream *stream = (PaSkeletonStream*)userData;
553
PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */
555
unsigned long framesProcessed;
557
PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
561
- generate timing information
562
- handle buffer slips
566
If you need to byte swap or shift inputBuffer to convert it into a
567
portaudio format, do it here.
572
PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */ );
575
depending on whether the host buffers are interleaved, non-interleaved
576
or a mixture, you will want to call PaUtil_SetInterleaved*Channels(),
577
PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here.
580
PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
581
PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor,
582
0, /* first channel of inputBuffer is channel 0 */
584
0 ); /* 0 - use inputChannelCount passed to init buffer processor */
586
PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
587
PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor,
588
0, /* first channel of outputBuffer is channel 0 */
590
0 ); /* 0 - use outputChannelCount passed to init buffer processor */
592
/* you must pass a valid value of callback result to PaUtil_EndBufferProcessing()
593
in general you would pass paContinue for normal operation, and
594
paComplete to drain the buffer processor's internal output buffer.
595
You can check whether the buffer processor's output buffer is empty
596
using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor )
598
callbackResult = paContinue;
599
framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
603
If you need to byte swap or shift outputBuffer to convert it to
604
host format, do it here.
607
PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
610
if( callbackResult == paContinue )
612
/* nothing special to do */
614
else if( callbackResult == paAbort )
616
/* IMPLEMENT ME - finish playback immediately */
618
/* once finished, call the finished callback */
619
if( stream->streamRepresentation.streamFinishedCallback != 0 )
620
stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
624
/* User callback has asked us to stop with paComplete or other non-zero value */
626
/* IMPLEMENT ME - finish playback once currently queued audio has completed */
628
/* once finished, call the finished callback */
629
if( stream->streamRepresentation.streamFinishedCallback != 0 )
630
stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
636
When CloseStream() is called, the multi-api layer ensures that
637
the stream has already been stopped or aborted.
639
static PaError CloseStream( PaStream* s )
641
PaError result = paNoError;
642
PaSkeletonStream *stream = (PaSkeletonStream*)s;
646
- additional stream closing + cleanup
649
PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
650
PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
651
PaUtil_FreeMemory( stream );
657
static PaError StartStream( PaStream *s )
659
PaError result = paNoError;
660
PaSkeletonStream *stream = (PaSkeletonStream*)s;
662
PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
664
/* IMPLEMENT ME, see portaudio.h for required behavior */
666
/* suppress unused function warning. the code in ExampleHostProcessingLoop or
667
something similar should be implemented to feed samples to and from the
668
host after StartStream() is called.
670
(void) ExampleHostProcessingLoop;
676
static PaError StopStream( PaStream *s )
678
PaError result = paNoError;
679
PaSkeletonStream *stream = (PaSkeletonStream*)s;
681
/* suppress unused variable warnings */
684
/* IMPLEMENT ME, see portaudio.h for required behavior */
690
static PaError AbortStream( PaStream *s )
692
PaError result = paNoError;
693
PaSkeletonStream *stream = (PaSkeletonStream*)s;
695
/* suppress unused variable warnings */
698
/* IMPLEMENT ME, see portaudio.h for required behavior */
704
static PaError IsStreamStopped( PaStream *s )
706
PaSkeletonStream *stream = (PaSkeletonStream*)s;
708
/* suppress unused variable warnings */
711
/* IMPLEMENT ME, see portaudio.h for required behavior */
717
static PaError IsStreamActive( PaStream *s )
719
PaSkeletonStream *stream = (PaSkeletonStream*)s;
721
/* suppress unused variable warnings */
724
/* IMPLEMENT ME, see portaudio.h for required behavior */
730
static PaTime GetStreamTime( PaStream *s )
732
PaSkeletonStream *stream = (PaSkeletonStream*)s;
734
/* suppress unused variable warnings */
737
/* IMPLEMENT ME, see portaudio.h for required behavior*/
743
static double GetStreamCpuLoad( PaStream* s )
745
PaSkeletonStream *stream = (PaSkeletonStream*)s;
747
return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
752
As separate stream interfaces are used for blocking and callback
753
streams, the following functions can be guaranteed to only be called
754
for blocking streams.
757
static PaError ReadStream( PaStream* s,
759
unsigned long frames )
761
PaSkeletonStream *stream = (PaSkeletonStream*)s;
763
/* suppress unused variable warnings */
768
/* IMPLEMENT ME, see portaudio.h for required behavior*/
774
static PaError WriteStream( PaStream* s,
776
unsigned long frames )
778
PaSkeletonStream *stream = (PaSkeletonStream*)s;
780
/* suppress unused variable warnings */
785
/* IMPLEMENT ME, see portaudio.h for required behavior*/
791
static signed long GetStreamReadAvailable( PaStream* s )
793
PaSkeletonStream *stream = (PaSkeletonStream*)s;
795
/* suppress unused variable warnings */
798
/* IMPLEMENT ME, see portaudio.h for required behavior*/
804
static signed long GetStreamWriteAvailable( PaStream* s )
806
PaSkeletonStream *stream = (PaSkeletonStream*)s;
808
/* suppress unused variable warnings */
811
/* IMPLEMENT ME, see portaudio.h for required behavior*/