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