1 /*
2 * $Id: pa_skeleton.c,v 1.1 2006/06/10 21:30:55 dmazzoni Exp $
3 * Portable Audio I/O Library skeleton implementation
4 * demonstrates how to use the common functions to implement support
5 * for a host API
6 *
7 * Based on the Open Source API proposed by Ross Bencina
8 * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
9 *
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:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * Any person wishing to distribute modifications to the Software is
22 * requested to send the modifications to the original developer so that
23 * they can be incorporated into the canonical version.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
28 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
29 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
30 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 */
33
34 /** @file
35 @brief Skeleton implementation of support for a host API.
36
37 @note This file is provided as a starting point for implementing support for
38 a new host API. IMPLEMENT ME comments are used to indicate functionality
39 which much be customised for each implementation.
40 */
41
42
43 #include <string.h> /* strlen() */
44
45 #include "pa_util.h"
46 #include "pa_allocation.h"
47 #include "pa_hostapi.h"
48 #include "pa_stream.h"
49 #include "pa_cpuload.h"
50 #include "pa_process.h"
51
52
53 /* prototypes for functions declared in this file */
54
55 #ifdef __cplusplus
56 extern "C"
57 {
58 #endif /* __cplusplus */
59
60 PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
61
62 #ifdef __cplusplus
63 }
64 #endif /* __cplusplus */
65
66
67 static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
68 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
69 const PaStreamParameters *inputParameters,
70 const PaStreamParameters *outputParameters,
71 double sampleRate );
72 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
73 PaStream** s,
74 const PaStreamParameters *inputParameters,
75 const PaStreamParameters *outputParameters,
76 double sampleRate,
77 unsigned long framesPerBuffer,
78 PaStreamFlags streamFlags,
79 PaStreamCallback *streamCallback,
80 void *userData );
81 static PaError CloseStream( PaStream* stream );
82 static PaError StartStream( PaStream *stream );
83 static PaError StopStream( PaStream *stream );
84 static PaError AbortStream( PaStream *stream );
85 static PaError IsStreamStopped( PaStream *s );
86 static PaError IsStreamActive( PaStream *stream );
87 static PaTime GetStreamTime( PaStream *stream );
88 static double GetStreamCpuLoad( PaStream* stream );
89 static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
90 static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
91 static signed long GetStreamReadAvailable( PaStream* stream );
92 static signed long GetStreamWriteAvailable( PaStream* stream );
93
94
95 /* IMPLEMENT ME: a macro like the following one should be used for reporting
96 host errors */
97 #define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \
98 PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )
99
100 /* PaSkeletonHostApiRepresentation - host api datastructure specific to this implementation */
101
102 typedef struct
103 {
104 PaUtilHostApiRepresentation inheritedHostApiRep;
105 PaUtilStreamInterface callbackStreamInterface;
106 PaUtilStreamInterface blockingStreamInterface;
107
108 PaUtilAllocationGroup *allocations;
109
110 /* implementation specific data goes here */
111 }
112 PaSkeletonHostApiRepresentation; /* IMPLEMENT ME: rename this */
113
114
PaSkeleton_Initialize(PaUtilHostApiRepresentation ** hostApi,PaHostApiIndex hostApiIndex)115 PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
116 {
117 PaError result = paNoError;
118 int i, deviceCount;
119 PaSkeletonHostApiRepresentation *skeletonHostApi;
120 PaDeviceInfo *deviceInfoArray;
121
122 skeletonHostApi = (PaSkeletonHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaSkeletonHostApiRepresentation) );
123 if( !skeletonHostApi )
124 {
125 result = paInsufficientMemory;
126 goto error;
127 }
128
129 skeletonHostApi->allocations = PaUtil_CreateAllocationGroup();
130 if( !skeletonHostApi->allocations )
131 {
132 result = paInsufficientMemory;
133 goto error;
134 }
135
136 *hostApi = &skeletonHostApi->inheritedHostApiRep;
137 (*hostApi)->info.structVersion = 1;
138 (*hostApi)->info.type = paInDevelopment; /* IMPLEMENT ME: change to correct type id */
139 (*hostApi)->info.name = "skeleton implementation"; /* IMPLEMENT ME: change to correct name */
140
141 (*hostApi)->info.defaultInputDevice = paNoDevice; /* IMPLEMENT ME */
142 (*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */
143
144 (*hostApi)->info.deviceCount = 0;
145
146 deviceCount = 0; /* IMPLEMENT ME */
147
148 if( deviceCount > 0 )
149 {
150 (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
151 skeletonHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
152 if( !(*hostApi)->deviceInfos )
153 {
154 result = paInsufficientMemory;
155 goto error;
156 }
157
158 /* allocate all device info structs in a contiguous block */
159 deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
160 skeletonHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount );
161 if( !deviceInfoArray )
162 {
163 result = paInsufficientMemory;
164 goto error;
165 }
166
167 for( i=0; i < deviceCount; ++i )
168 {
169 PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
170 deviceInfo->structVersion = 2;
171 deviceInfo->hostApi = hostApiIndex;
172 deviceInfo->name = 0; /* IMPLEMENT ME: allocate block and copy name eg:
173 deviceName = (char*)PaUtil_GroupAllocateMemory( skeletonHostApi->allocations, strlen(srcName) + 1 );
174 if( !deviceName )
175 {
176 result = paInsufficientMemory;
177 goto error;
178 }
179 strcpy( deviceName, srcName );
180 deviceInfo->name = deviceName;
181 */
182
183 deviceInfo->maxInputChannels = 0; /* IMPLEMENT ME */
184 deviceInfo->maxOutputChannels = 0; /* IMPLEMENT ME */
185
186 deviceInfo->defaultLowInputLatency = 0.; /* IMPLEMENT ME */
187 deviceInfo->defaultLowOutputLatency = 0.; /* IMPLEMENT ME */
188 deviceInfo->defaultHighInputLatency = 0.; /* IMPLEMENT ME */
189 deviceInfo->defaultHighOutputLatency = 0.; /* IMPLEMENT ME */
190
191 deviceInfo->defaultSampleRate = 0.; /* IMPLEMENT ME */
192
193 (*hostApi)->deviceInfos[i] = deviceInfo;
194 ++(*hostApi)->info.deviceCount;
195 }
196 }
197
198 (*hostApi)->Terminate = Terminate;
199 (*hostApi)->OpenStream = OpenStream;
200 (*hostApi)->IsFormatSupported = IsFormatSupported;
201
202 PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, CloseStream, StartStream,
203 StopStream, AbortStream, IsStreamStopped, IsStreamActive,
204 GetStreamTime, GetStreamCpuLoad,
205 PaUtil_DummyRead, PaUtil_DummyWrite,
206 PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
207
208 PaUtil_InitializeStreamInterface( &skeletonHostApi->blockingStreamInterface, CloseStream, StartStream,
209 StopStream, AbortStream, IsStreamStopped, IsStreamActive,
210 GetStreamTime, PaUtil_DummyGetCpuLoad,
211 ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
212
213 return result;
214
215 error:
216 if( skeletonHostApi )
217 {
218 if( skeletonHostApi->allocations )
219 {
220 PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
221 PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
222 }
223
224 PaUtil_FreeMemory( skeletonHostApi );
225 }
226 return result;
227 }
228
229
Terminate(struct PaUtilHostApiRepresentation * hostApi)230 static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
231 {
232 PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;
233
234 /*
235 IMPLEMENT ME:
236 - clean up any resources not handled by the allocation group
237 */
238
239 if( skeletonHostApi->allocations )
240 {
241 PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
242 PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
243 }
244
245 PaUtil_FreeMemory( skeletonHostApi );
246 }
247
248
IsFormatSupported(struct PaUtilHostApiRepresentation * hostApi,const PaStreamParameters * inputParameters,const PaStreamParameters * outputParameters,double sampleRate)249 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
250 const PaStreamParameters *inputParameters,
251 const PaStreamParameters *outputParameters,
252 double sampleRate )
253 {
254 int inputChannelCount, outputChannelCount;
255 PaSampleFormat inputSampleFormat, outputSampleFormat;
256
257 if( inputParameters )
258 {
259 inputChannelCount = inputParameters->channelCount;
260 inputSampleFormat = inputParameters->sampleFormat;
261
262 /* all standard sample formats are supported by the buffer adapter,
263 this implementation doesn't support any custom sample formats */
264 if( inputSampleFormat & paCustomFormat )
265 return paSampleFormatNotSupported;
266
267 /* unless alternate device specification is supported, reject the use of
268 paUseHostApiSpecificDeviceSpecification */
269
270 if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
271 return paInvalidDevice;
272
273 /* check that input device can support inputChannelCount */
274 if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
275 return paInvalidChannelCount;
276
277 /* validate inputStreamInfo */
278 if( inputParameters->hostApiSpecificStreamInfo )
279 return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
280 }
281 else
282 {
283 inputChannelCount = 0;
284 }
285
286 if( outputParameters )
287 {
288 outputChannelCount = outputParameters->channelCount;
289 outputSampleFormat = outputParameters->sampleFormat;
290
291 /* all standard sample formats are supported by the buffer adapter,
292 this implementation doesn't support any custom sample formats */
293 if( outputSampleFormat & paCustomFormat )
294 return paSampleFormatNotSupported;
295
296 /* unless alternate device specification is supported, reject the use of
297 paUseHostApiSpecificDeviceSpecification */
298
299 if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
300 return paInvalidDevice;
301
302 /* check that output device can support outputChannelCount */
303 if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
304 return paInvalidChannelCount;
305
306 /* validate outputStreamInfo */
307 if( outputParameters->hostApiSpecificStreamInfo )
308 return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
309 }
310 else
311 {
312 outputChannelCount = 0;
313 }
314
315 /*
316 IMPLEMENT ME:
317
318 - if a full duplex stream is requested, check that the combination
319 of input and output parameters is supported if necessary
320
321 - check that the device supports sampleRate
322
323 Because the buffer adapter handles conversion between all standard
324 sample formats, the following checks are only required if paCustomFormat
325 is implemented, or under some other unusual conditions.
326
327 - check that input device can support inputSampleFormat, or that
328 we have the capability to convert from inputSampleFormat to
329 a native format
330
331 - check that output device can support outputSampleFormat, or that
332 we have the capability to convert from outputSampleFormat to
333 a native format
334 */
335
336
337 /* suppress unused variable warnings */
338 (void) sampleRate;
339
340 return paFormatIsSupported;
341 }
342
343 /* PaSkeletonStream - a stream data structure specifically for this implementation */
344
345 typedef struct PaSkeletonStream
346 { /* IMPLEMENT ME: rename this */
347 PaUtilStreamRepresentation streamRepresentation;
348 PaUtilCpuLoadMeasurer cpuLoadMeasurer;
349 PaUtilBufferProcessor bufferProcessor;
350
351 /* IMPLEMENT ME:
352 - implementation specific data goes here
353 */
354 unsigned long framesPerHostCallback; /* just an example */
355 }
356 PaSkeletonStream;
357
358 /* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
359
OpenStream(struct PaUtilHostApiRepresentation * hostApi,PaStream ** s,const PaStreamParameters * inputParameters,const PaStreamParameters * outputParameters,double sampleRate,unsigned long framesPerBuffer,PaStreamFlags streamFlags,PaStreamCallback * streamCallback,void * userData)360 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
361 PaStream** s,
362 const PaStreamParameters *inputParameters,
363 const PaStreamParameters *outputParameters,
364 double sampleRate,
365 unsigned long framesPerBuffer,
366 PaStreamFlags streamFlags,
367 PaStreamCallback *streamCallback,
368 void *userData )
369 {
370 PaError result = paNoError;
371 PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;
372 PaSkeletonStream *stream = 0;
373 unsigned long framesPerHostBuffer = framesPerBuffer; /* these may not be equivalent for all implementations */
374 int inputChannelCount, outputChannelCount;
375 PaSampleFormat inputSampleFormat, outputSampleFormat;
376 PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
377
378
379 if( inputParameters )
380 {
381 inputChannelCount = inputParameters->channelCount;
382 inputSampleFormat = inputParameters->sampleFormat;
383
384 /* unless alternate device specification is supported, reject the use of
385 paUseHostApiSpecificDeviceSpecification */
386
387 if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
388 return paInvalidDevice;
389
390 /* check that input device can support inputChannelCount */
391 if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
392 return paInvalidChannelCount;
393
394 /* validate inputStreamInfo */
395 if( inputParameters->hostApiSpecificStreamInfo )
396 return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
397
398 /* IMPLEMENT ME - establish which host formats are available */
399 hostInputSampleFormat =
400 PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat );
401 }
402 else
403 {
404 inputChannelCount = 0;
405 inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */
406 }
407
408 if( outputParameters )
409 {
410 outputChannelCount = outputParameters->channelCount;
411 outputSampleFormat = outputParameters->sampleFormat;
412
413 /* unless alternate device specification is supported, reject the use of
414 paUseHostApiSpecificDeviceSpecification */
415
416 if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
417 return paInvalidDevice;
418
419 /* check that output device can support inputChannelCount */
420 if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
421 return paInvalidChannelCount;
422
423 /* validate outputStreamInfo */
424 if( outputParameters->hostApiSpecificStreamInfo )
425 return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
426
427 /* IMPLEMENT ME - establish which host formats are available */
428 hostOutputSampleFormat =
429 PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat );
430 }
431 else
432 {
433 outputChannelCount = 0;
434 outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */
435 }
436
437 /*
438 IMPLEMENT ME:
439
440 ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? )
441
442 - check that input device can support inputSampleFormat, or that
443 we have the capability to convert from outputSampleFormat to
444 a native format
445
446 - check that output device can support outputSampleFormat, or that
447 we have the capability to convert from outputSampleFormat to
448 a native format
449
450 - if a full duplex stream is requested, check that the combination
451 of input and output parameters is supported
452
453 - check that the device supports sampleRate
454
455 - alter sampleRate to a close allowable rate if possible / necessary
456
457 - validate suggestedInputLatency and suggestedOutputLatency parameters,
458 use default values where necessary
459 */
460
461
462
463
464 /* validate platform specific flags */
465 if( (streamFlags & paPlatformSpecificFlags) != 0 )
466 return paInvalidFlag; /* unexpected platform specific flag */
467
468
469 stream = (PaSkeletonStream*)PaUtil_AllocateMemory( sizeof(PaSkeletonStream) );
470 if( !stream )
471 {
472 result = paInsufficientMemory;
473 goto error;
474 }
475
476 if( streamCallback )
477 {
478 PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
479 &skeletonHostApi->callbackStreamInterface, streamCallback, userData );
480 }
481 else
482 {
483 PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
484 &skeletonHostApi->blockingStreamInterface, streamCallback, userData );
485 }
486
487 PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
488
489
490 /* we assume a fixed host buffer size in this example, but the buffer processor
491 can also support bounded and unknown host buffer sizes by passing
492 paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of
493 paUtilFixedHostBufferSize below. */
494
495 result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
496 inputChannelCount, inputSampleFormat, hostInputSampleFormat,
497 outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
498 sampleRate, streamFlags, framesPerBuffer,
499 framesPerHostBuffer, paUtilFixedHostBufferSize,
500 streamCallback, userData );
501 if( result != paNoError )
502 goto error;
503
504
505 /*
506 IMPLEMENT ME: initialise the following fields with estimated or actual
507 values.
508 */
509 stream->streamRepresentation.streamInfo.inputLatency =
510 PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor);
511 stream->streamRepresentation.streamInfo.outputLatency =
512 PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor);
513 stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
514
515
516 /*
517 IMPLEMENT ME:
518 - additional stream setup + opening
519 */
520
521 stream->framesPerHostCallback = framesPerHostBuffer;
522
523 *s = (PaStream*)stream;
524
525 return result;
526
527 error:
528 if( stream )
529 PaUtil_FreeMemory( stream );
530
531 return result;
532 }
533
534 /*
535 ExampleHostProcessingLoop() illustrates the kind of processing which may
536 occur in a host implementation.
537
538 */
ExampleHostProcessingLoop(void * inputBuffer,void * outputBuffer,void * userData)539 static void ExampleHostProcessingLoop( void *inputBuffer, void *outputBuffer, void *userData )
540 {
541 PaSkeletonStream *stream = (PaSkeletonStream*)userData;
542 PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */
543 int callbackResult;
544 unsigned long framesProcessed;
545
546 PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
547
548 /*
549 IMPLEMENT ME:
550 - generate timing information
551 - handle buffer slips
552 */
553
554 /*
555 If you need to byte swap or shift inputBuffer to convert it into a
556 portaudio format, do it here.
557 */
558
559
560
561 PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */ );
562
563 /*
564 depending on whether the host buffers are interleaved, non-interleaved
565 or a mixture, you will want to call PaUtil_SetInterleaved*Channels(),
566 PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here.
567 */
568
569 PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
570 PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor,
571 0, /* first channel of inputBuffer is channel 0 */
572 inputBuffer,
573 0 ); /* 0 - use inputChannelCount passed to init buffer processor */
574
575 PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
576 PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor,
577 0, /* first channel of outputBuffer is channel 0 */
578 outputBuffer,
579 0 ); /* 0 - use outputChannelCount passed to init buffer processor */
580
581 /* you must pass a valid value of callback result to PaUtil_EndBufferProcessing()
582 in general you would pass paContinue for normal operation, and
583 paComplete to drain the buffer processor's internal output buffer.
584 You can check whether the buffer processor's output buffer is empty
585 using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor )
586 */
587 callbackResult = paContinue;
588 framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
589
590
591 /*
592 If you need to byte swap or shift outputBuffer to convert it to
593 host format, do it here.
594 */
595
596 PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
597
598
599 if( callbackResult == paContinue )
600 {
601 /* nothing special to do */
602 }
603 else if( callbackResult == paAbort )
604 {
605 /* IMPLEMENT ME - finish playback immediately */
606
607 /* once finished, call the finished callback */
608 if( stream->streamRepresentation.streamFinishedCallback != 0 )
609 stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
610 }
611 else
612 {
613 /* User callback has asked us to stop with paComplete or other non-zero value */
614
615 /* IMPLEMENT ME - finish playback once currently queued audio has completed */
616
617 /* once finished, call the finished callback */
618 if( stream->streamRepresentation.streamFinishedCallback != 0 )
619 stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
620 }
621 }
622
623
624 /*
625 When CloseStream() is called, the multi-api layer ensures that
626 the stream has already been stopped or aborted.
627 */
CloseStream(PaStream * s)628 static PaError CloseStream( PaStream* s )
629 {
630 PaError result = paNoError;
631 PaSkeletonStream *stream = (PaSkeletonStream*)s;
632
633 /*
634 IMPLEMENT ME:
635 - additional stream closing + cleanup
636 */
637
638 PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
639 PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
640 PaUtil_FreeMemory( stream );
641
642 return result;
643 }
644
645
StartStream(PaStream * s)646 static PaError StartStream( PaStream *s )
647 {
648 PaError result = paNoError;
649 PaSkeletonStream *stream = (PaSkeletonStream*)s;
650
651 PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
652
653 /* IMPLEMENT ME, see portaudio.h for required behavior */
654
655 /* suppress unused function warning. the code in ExampleHostProcessingLoop or
656 something similar should be implemented to feed samples to and from the
657 host after StartStream() is called.
658 */
659 (void) ExampleHostProcessingLoop;
660
661 return result;
662 }
663
664
StopStream(PaStream * s)665 static PaError StopStream( PaStream *s )
666 {
667 PaError result = paNoError;
668 PaSkeletonStream *stream = (PaSkeletonStream*)s;
669
670 /* suppress unused variable warnings */
671 (void) stream;
672
673 /* IMPLEMENT ME, see portaudio.h for required behavior */
674
675 return result;
676 }
677
678
AbortStream(PaStream * s)679 static PaError AbortStream( PaStream *s )
680 {
681 PaError result = paNoError;
682 PaSkeletonStream *stream = (PaSkeletonStream*)s;
683
684 /* suppress unused variable warnings */
685 (void) stream;
686
687 /* IMPLEMENT ME, see portaudio.h for required behavior */
688
689 return result;
690 }
691
692
IsStreamStopped(PaStream * s)693 static PaError IsStreamStopped( PaStream *s )
694 {
695 PaSkeletonStream *stream = (PaSkeletonStream*)s;
696
697 /* suppress unused variable warnings */
698 (void) stream;
699
700 /* IMPLEMENT ME, see portaudio.h for required behavior */
701
702 return 0;
703 }
704
705
IsStreamActive(PaStream * s)706 static PaError IsStreamActive( PaStream *s )
707 {
708 PaSkeletonStream *stream = (PaSkeletonStream*)s;
709
710 /* suppress unused variable warnings */
711 (void) stream;
712
713 /* IMPLEMENT ME, see portaudio.h for required behavior */
714
715 return 0;
716 }
717
718
GetStreamTime(PaStream * s)719 static PaTime GetStreamTime( PaStream *s )
720 {
721 PaSkeletonStream *stream = (PaSkeletonStream*)s;
722
723 /* suppress unused variable warnings */
724 (void) stream;
725
726 /* IMPLEMENT ME, see portaudio.h for required behavior*/
727
728 return 0;
729 }
730
731
GetStreamCpuLoad(PaStream * s)732 static double GetStreamCpuLoad( PaStream* s )
733 {
734 PaSkeletonStream *stream = (PaSkeletonStream*)s;
735
736 return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
737 }
738
739
740 /*
741 As separate stream interfaces are used for blocking and callback
742 streams, the following functions can be guaranteed to only be called
743 for blocking streams.
744 */
745
ReadStream(PaStream * s,void * buffer,unsigned long frames)746 static PaError ReadStream( PaStream* s,
747 void *buffer,
748 unsigned long frames )
749 {
750 PaSkeletonStream *stream = (PaSkeletonStream*)s;
751
752 /* suppress unused variable warnings */
753 (void) buffer;
754 (void) frames;
755 (void) stream;
756
757 /* IMPLEMENT ME, see portaudio.h for required behavior*/
758
759 return paNoError;
760 }
761
762
WriteStream(PaStream * s,const void * buffer,unsigned long frames)763 static PaError WriteStream( PaStream* s,
764 const void *buffer,
765 unsigned long frames )
766 {
767 PaSkeletonStream *stream = (PaSkeletonStream*)s;
768
769 /* suppress unused variable warnings */
770 (void) buffer;
771 (void) frames;
772 (void) stream;
773
774 /* IMPLEMENT ME, see portaudio.h for required behavior*/
775
776 return paNoError;
777 }
778
779
GetStreamReadAvailable(PaStream * s)780 static signed long GetStreamReadAvailable( PaStream* s )
781 {
782 PaSkeletonStream *stream = (PaSkeletonStream*)s;
783
784 /* suppress unused variable warnings */
785 (void) stream;
786
787 /* IMPLEMENT ME, see portaudio.h for required behavior*/
788
789 return 0;
790 }
791
792
GetStreamWriteAvailable(PaStream * s)793 static signed long GetStreamWriteAvailable( PaStream* s )
794 {
795 PaSkeletonStream *stream = (PaSkeletonStream*)s;
796
797 /* suppress unused variable warnings */
798 (void) stream;
799
800 /* IMPLEMENT ME, see portaudio.h for required behavior*/
801
802 return 0;
803 }
804
805
806
807
808