1 /*
2  * $Id$
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  * 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.
28  */
29 
30 /*
31  * The text above constitutes the entire PortAudio license; however,
32  * the PortAudio community also makes the following non-binding requests:
33  *
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
38  * license above.
39  */
40 
41 /** @file
42  @ingroup common_src
43 
44  @brief Skeleton implementation of support for a host API.
45 
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.
48 
49  @note IMPLEMENT ME comments are used to indicate functionality
50  which much be customised for each implementation.
51 */
52 
53 
54 #include <string.h> /* strlen() */
55 
56 #include "pa_util.h"
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"
62 
63 
64 /* prototypes for functions declared in this file */
65 
66 #ifdef __cplusplus
67 extern "C"
68 {
69 #endif /* __cplusplus */
70 
71 PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
72 
73 #ifdef __cplusplus
74 }
75 #endif /* __cplusplus */
76 
77 
78 static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
79 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
80                                   const PaStreamParameters *inputParameters,
81                                   const PaStreamParameters *outputParameters,
82                                   double sampleRate );
83 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
84                            PaStream** s,
85                            const PaStreamParameters *inputParameters,
86                            const PaStreamParameters *outputParameters,
87                            double sampleRate,
88                            unsigned long framesPerBuffer,
89                            PaStreamFlags streamFlags,
90                            PaStreamCallback *streamCallback,
91                            void *userData );
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 );
104 
105 
106 /* IMPLEMENT ME: a macro like the following one should be used for reporting
107  host errors */
108 #define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \
109     PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )
110 
111 /* PaSkeletonHostApiRepresentation - host api datastructure specific to this implementation */
112 
113 typedef struct
114 {
115     PaUtilHostApiRepresentation inheritedHostApiRep;
116     PaUtilStreamInterface callbackStreamInterface;
117     PaUtilStreamInterface blockingStreamInterface;
118 
119     PaUtilAllocationGroup *allocations;
120 
121     /* implementation specific data goes here */
122 }
123 PaSkeletonHostApiRepresentation;  /* IMPLEMENT ME: rename this */
124 
125 
PaSkeleton_Initialize(PaUtilHostApiRepresentation ** hostApi,PaHostApiIndex hostApiIndex)126 PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
127 {
128     PaError result = paNoError;
129     int i, deviceCount;
130     PaSkeletonHostApiRepresentation *skeletonHostApi;
131     PaDeviceInfo *deviceInfoArray;
132 
133     skeletonHostApi = (PaSkeletonHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaSkeletonHostApiRepresentation) );
134     if( !skeletonHostApi )
135     {
136         result = paInsufficientMemory;
137         goto error;
138     }
139 
140     skeletonHostApi->allocations = PaUtil_CreateAllocationGroup();
141     if( !skeletonHostApi->allocations )
142     {
143         result = paInsufficientMemory;
144         goto error;
145     }
146 
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 */
151 
152     (*hostApi)->info.defaultInputDevice = paNoDevice;  /* IMPLEMENT ME */
153     (*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */
154 
155     (*hostApi)->info.deviceCount = 0;
156 
157     deviceCount = 0; /* IMPLEMENT ME */
158 
159     if( deviceCount > 0 )
160     {
161         (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
162                 skeletonHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
163         if( !(*hostApi)->deviceInfos )
164         {
165             result = paInsufficientMemory;
166             goto error;
167         }
168 
169         /* allocate all device info structs in a contiguous block */
170         deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
171                 skeletonHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount );
172         if( !deviceInfoArray )
173         {
174             result = paInsufficientMemory;
175             goto error;
176         }
177 
178         for( i=0; i < deviceCount; ++i )
179         {
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 );
185                 if( !deviceName )
186                 {
187                     result = paInsufficientMemory;
188                     goto error;
189                 }
190                 strcpy( deviceName, srcName );
191                 deviceInfo->name = deviceName;
192             */
193 
194             deviceInfo->maxInputChannels = 0;  /* IMPLEMENT ME */
195             deviceInfo->maxOutputChannels = 0;  /* IMPLEMENT ME */
196 
197             deviceInfo->defaultLowInputLatency = 0.;  /* IMPLEMENT ME */
198             deviceInfo->defaultLowOutputLatency = 0.;  /* IMPLEMENT ME */
199             deviceInfo->defaultHighInputLatency = 0.;  /* IMPLEMENT ME */
200             deviceInfo->defaultHighOutputLatency = 0.;  /* IMPLEMENT ME */
201 
202             deviceInfo->defaultSampleRate = 0.; /* IMPLEMENT ME */
203 
204             (*hostApi)->deviceInfos[i] = deviceInfo;
205             ++(*hostApi)->info.deviceCount;
206         }
207     }
208 
209     (*hostApi)->Terminate = Terminate;
210     (*hostApi)->OpenStream = OpenStream;
211     (*hostApi)->IsFormatSupported = IsFormatSupported;
212 
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 );
218 
219     PaUtil_InitializeStreamInterface( &skeletonHostApi->blockingStreamInterface, CloseStream, StartStream,
220                                       StopStream, AbortStream, IsStreamStopped, IsStreamActive,
221                                       GetStreamTime, PaUtil_DummyGetCpuLoad,
222                                       ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
223 
224     return result;
225 
226 error:
227     if( skeletonHostApi )
228     {
229         if( skeletonHostApi->allocations )
230         {
231             PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
232             PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
233         }
234 
235         PaUtil_FreeMemory( skeletonHostApi );
236     }
237     return result;
238 }
239 
240 
Terminate(struct PaUtilHostApiRepresentation * hostApi)241 static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
242 {
243     PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;
244 
245     /*
246         IMPLEMENT ME:
247             - clean up any resources not handled by the allocation group
248     */
249 
250     if( skeletonHostApi->allocations )
251     {
252         PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
253         PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
254     }
255 
256     PaUtil_FreeMemory( skeletonHostApi );
257 }
258 
259 
IsFormatSupported(struct PaUtilHostApiRepresentation * hostApi,const PaStreamParameters * inputParameters,const PaStreamParameters * outputParameters,double sampleRate)260 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
261                                   const PaStreamParameters *inputParameters,
262                                   const PaStreamParameters *outputParameters,
263                                   double sampleRate )
264 {
265     int inputChannelCount, outputChannelCount;
266     PaSampleFormat inputSampleFormat, outputSampleFormat;
267 
268     if( inputParameters )
269     {
270         inputChannelCount = inputParameters->channelCount;
271         inputSampleFormat = inputParameters->sampleFormat;
272 
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;
277 
278         /* unless alternate device specification is supported, reject the use of
279             paUseHostApiSpecificDeviceSpecification */
280 
281         if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
282             return paInvalidDevice;
283 
284         /* check that input device can support inputChannelCount */
285         if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
286             return paInvalidChannelCount;
287 
288         /* validate inputStreamInfo */
289         if( inputParameters->hostApiSpecificStreamInfo )
290             return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
291     }
292     else
293     {
294         inputChannelCount = 0;
295     }
296 
297     if( outputParameters )
298     {
299         outputChannelCount = outputParameters->channelCount;
300         outputSampleFormat = outputParameters->sampleFormat;
301 
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;
306 
307         /* unless alternate device specification is supported, reject the use of
308             paUseHostApiSpecificDeviceSpecification */
309 
310         if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
311             return paInvalidDevice;
312 
313         /* check that output device can support outputChannelCount */
314         if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
315             return paInvalidChannelCount;
316 
317         /* validate outputStreamInfo */
318         if( outputParameters->hostApiSpecificStreamInfo )
319             return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
320     }
321     else
322     {
323         outputChannelCount = 0;
324     }
325 
326     /*
327         IMPLEMENT ME:
328 
329             - if a full duplex stream is requested, check that the combination
330                 of input and output parameters is supported if necessary
331 
332             - check that the device supports sampleRate
333 
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.
337 
338             - check that input device can support inputSampleFormat, or that
339                 we have the capability to convert from inputSampleFormat to
340                 a native format
341 
342             - check that output device can support outputSampleFormat, or that
343                 we have the capability to convert from outputSampleFormat to
344                 a native format
345     */
346 
347 
348     /* suppress unused variable warnings */
349     (void) sampleRate;
350 
351     return paFormatIsSupported;
352 }
353 
354 /* PaSkeletonStream - a stream data structure specifically for this implementation */
355 
356 typedef struct PaSkeletonStream
357 { /* IMPLEMENT ME: rename this */
358     PaUtilStreamRepresentation streamRepresentation;
359     PaUtilCpuLoadMeasurer cpuLoadMeasurer;
360     PaUtilBufferProcessor bufferProcessor;
361 
362     /* IMPLEMENT ME:
363             - implementation specific data goes here
364     */
365     unsigned long framesPerHostCallback; /* just an example */
366 }
367 PaSkeletonStream;
368 
369 /* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
370 
OpenStream(struct PaUtilHostApiRepresentation * hostApi,PaStream ** s,const PaStreamParameters * inputParameters,const PaStreamParameters * outputParameters,double sampleRate,unsigned long framesPerBuffer,PaStreamFlags streamFlags,PaStreamCallback * streamCallback,void * userData)371 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
372                            PaStream** s,
373                            const PaStreamParameters *inputParameters,
374                            const PaStreamParameters *outputParameters,
375                            double sampleRate,
376                            unsigned long framesPerBuffer,
377                            PaStreamFlags streamFlags,
378                            PaStreamCallback *streamCallback,
379                            void *userData )
380 {
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;
388 
389 
390     if( inputParameters )
391     {
392         inputChannelCount = inputParameters->channelCount;
393         inputSampleFormat = inputParameters->sampleFormat;
394 
395         /* unless alternate device specification is supported, reject the use of
396             paUseHostApiSpecificDeviceSpecification */
397 
398         if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
399             return paInvalidDevice;
400 
401         /* check that input device can support inputChannelCount */
402         if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
403             return paInvalidChannelCount;
404 
405         /* validate inputStreamInfo */
406         if( inputParameters->hostApiSpecificStreamInfo )
407             return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
408 
409         /* IMPLEMENT ME - establish which  host formats are available */
410         hostInputSampleFormat =
411             PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat );
412     }
413     else
414     {
415         inputChannelCount = 0;
416         inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */
417     }
418 
419     if( outputParameters )
420     {
421         outputChannelCount = outputParameters->channelCount;
422         outputSampleFormat = outputParameters->sampleFormat;
423 
424         /* unless alternate device specification is supported, reject the use of
425             paUseHostApiSpecificDeviceSpecification */
426 
427         if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
428             return paInvalidDevice;
429 
430         /* check that output device can support inputChannelCount */
431         if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
432             return paInvalidChannelCount;
433 
434         /* validate outputStreamInfo */
435         if( outputParameters->hostApiSpecificStreamInfo )
436             return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
437 
438         /* IMPLEMENT ME - establish which  host formats are available */
439         hostOutputSampleFormat =
440             PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat );
441     }
442     else
443     {
444         outputChannelCount = 0;
445         outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */
446     }
447 
448     /*
449         IMPLEMENT ME:
450 
451         ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? )
452 
453             - check that input device can support inputSampleFormat, or that
454                 we have the capability to convert from outputSampleFormat to
455                 a native format
456 
457             - check that output device can support outputSampleFormat, or that
458                 we have the capability to convert from outputSampleFormat to
459                 a native format
460 
461             - if a full duplex stream is requested, check that the combination
462                 of input and output parameters is supported
463 
464             - check that the device supports sampleRate
465 
466             - alter sampleRate to a close allowable rate if possible / necessary
467 
468             - validate suggestedInputLatency and suggestedOutputLatency parameters,
469                 use default values where necessary
470     */
471 
472 
473 
474 
475     /* validate platform specific flags */
476     if( (streamFlags & paPlatformSpecificFlags) != 0 )
477         return paInvalidFlag; /* unexpected platform specific flag */
478 
479 
480     stream = (PaSkeletonStream*)PaUtil_AllocateMemory( sizeof(PaSkeletonStream) );
481     if( !stream )
482     {
483         result = paInsufficientMemory;
484         goto error;
485     }
486 
487     if( streamCallback )
488     {
489         PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
490                                                &skeletonHostApi->callbackStreamInterface, streamCallback, userData );
491     }
492     else
493     {
494         PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
495                                                &skeletonHostApi->blockingStreamInterface, streamCallback, userData );
496     }
497 
498     PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
499 
500 
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. */
505 
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 )
513         goto error;
514 
515 
516     /*
517         IMPLEMENT ME: initialise the following fields with estimated or actual
518         values.
519     */
520     stream->streamRepresentation.streamInfo.inputLatency =
521             (PaTime)PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor) / sampleRate; /* inputLatency is specified in _seconds_ */
522     stream->streamRepresentation.streamInfo.outputLatency =
523             (PaTime)PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor) / sampleRate; /* outputLatency is specified in _seconds_ */
524     stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
525 
526 
527     /*
528         IMPLEMENT ME:
529             - additional stream setup + opening
530     */
531 
532     stream->framesPerHostCallback = framesPerHostBuffer;
533 
534     *s = (PaStream*)stream;
535 
536     return result;
537 
538 error:
539     if( stream )
540         PaUtil_FreeMemory( stream );
541 
542     return result;
543 }
544 
545 /*
546     ExampleHostProcessingLoop() illustrates the kind of processing which may
547     occur in a host implementation.
548 
549 */
ExampleHostProcessingLoop(void * inputBuffer,void * outputBuffer,void * userData)550 static void ExampleHostProcessingLoop( void *inputBuffer, void *outputBuffer, void *userData )
551 {
552     PaSkeletonStream *stream = (PaSkeletonStream*)userData;
553     PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */
554     int callbackResult;
555     unsigned long framesProcessed;
556 
557     PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
558 
559     /*
560         IMPLEMENT ME:
561             - generate timing information
562             - handle buffer slips
563     */
564 
565     /*
566         If you need to byte swap or shift inputBuffer to convert it into a
567         portaudio format, do it here.
568     */
569 
570 
571 
572     PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */ );
573 
574     /*
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.
578     */
579 
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 */
583             inputBuffer,
584             0 ); /* 0 - use inputChannelCount passed to init buffer processor */
585 
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 */
589             outputBuffer,
590             0 ); /* 0 - use outputChannelCount passed to init buffer processor */
591 
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 )
597     */
598     callbackResult = paContinue;
599     framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
600 
601 
602     /*
603         If you need to byte swap or shift outputBuffer to convert it to
604         host format, do it here.
605     */
606 
607     PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
608 
609 
610     if( callbackResult == paContinue )
611     {
612         /* nothing special to do */
613     }
614     else if( callbackResult == paAbort )
615     {
616         /* IMPLEMENT ME - finish playback immediately  */
617 
618         /* once finished, call the finished callback */
619         if( stream->streamRepresentation.streamFinishedCallback != 0 )
620             stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
621     }
622     else
623     {
624         /* User callback has asked us to stop with paComplete or other non-zero value */
625 
626         /* IMPLEMENT ME - finish playback once currently queued audio has completed  */
627 
628         /* once finished, call the finished callback */
629         if( stream->streamRepresentation.streamFinishedCallback != 0 )
630             stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
631     }
632 }
633 
634 
635 /*
636     When CloseStream() is called, the multi-api layer ensures that
637     the stream has already been stopped or aborted.
638 */
CloseStream(PaStream * s)639 static PaError CloseStream( PaStream* s )
640 {
641     PaError result = paNoError;
642     PaSkeletonStream *stream = (PaSkeletonStream*)s;
643 
644     /*
645         IMPLEMENT ME:
646             - additional stream closing + cleanup
647     */
648 
649     PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
650     PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
651     PaUtil_FreeMemory( stream );
652 
653     return result;
654 }
655 
656 
StartStream(PaStream * s)657 static PaError StartStream( PaStream *s )
658 {
659     PaError result = paNoError;
660     PaSkeletonStream *stream = (PaSkeletonStream*)s;
661 
662     PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
663 
664     /* IMPLEMENT ME, see portaudio.h for required behavior */
665 
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.
669     */
670     (void) ExampleHostProcessingLoop;
671 
672     return result;
673 }
674 
675 
StopStream(PaStream * s)676 static PaError StopStream( PaStream *s )
677 {
678     PaError result = paNoError;
679     PaSkeletonStream *stream = (PaSkeletonStream*)s;
680 
681     /* suppress unused variable warnings */
682     (void) stream;
683 
684     /* IMPLEMENT ME, see portaudio.h for required behavior */
685 
686     return result;
687 }
688 
689 
AbortStream(PaStream * s)690 static PaError AbortStream( PaStream *s )
691 {
692     PaError result = paNoError;
693     PaSkeletonStream *stream = (PaSkeletonStream*)s;
694 
695     /* suppress unused variable warnings */
696     (void) stream;
697 
698     /* IMPLEMENT ME, see portaudio.h for required behavior */
699 
700     return result;
701 }
702 
703 
IsStreamStopped(PaStream * s)704 static PaError IsStreamStopped( PaStream *s )
705 {
706     PaSkeletonStream *stream = (PaSkeletonStream*)s;
707 
708     /* suppress unused variable warnings */
709     (void) stream;
710 
711     /* IMPLEMENT ME, see portaudio.h for required behavior */
712 
713     return 0;
714 }
715 
716 
IsStreamActive(PaStream * s)717 static PaError IsStreamActive( PaStream *s )
718 {
719     PaSkeletonStream *stream = (PaSkeletonStream*)s;
720 
721     /* suppress unused variable warnings */
722     (void) stream;
723 
724     /* IMPLEMENT ME, see portaudio.h for required behavior */
725 
726     return 0;
727 }
728 
729 
GetStreamTime(PaStream * s)730 static PaTime GetStreamTime( PaStream *s )
731 {
732     PaSkeletonStream *stream = (PaSkeletonStream*)s;
733 
734     /* suppress unused variable warnings */
735     (void) stream;
736 
737     /* IMPLEMENT ME, see portaudio.h for required behavior*/
738 
739     return 0;
740 }
741 
742 
GetStreamCpuLoad(PaStream * s)743 static double GetStreamCpuLoad( PaStream* s )
744 {
745     PaSkeletonStream *stream = (PaSkeletonStream*)s;
746 
747     return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
748 }
749 
750 
751 /*
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.
755 */
756 
ReadStream(PaStream * s,void * buffer,unsigned long frames)757 static PaError ReadStream( PaStream* s,
758                            void *buffer,
759                            unsigned long frames )
760 {
761     PaSkeletonStream *stream = (PaSkeletonStream*)s;
762 
763     /* suppress unused variable warnings */
764     (void) buffer;
765     (void) frames;
766     (void) stream;
767 
768     /* IMPLEMENT ME, see portaudio.h for required behavior*/
769 
770     return paNoError;
771 }
772 
773 
WriteStream(PaStream * s,const void * buffer,unsigned long frames)774 static PaError WriteStream( PaStream* s,
775                             const void *buffer,
776                             unsigned long frames )
777 {
778     PaSkeletonStream *stream = (PaSkeletonStream*)s;
779 
780     /* suppress unused variable warnings */
781     (void) buffer;
782     (void) frames;
783     (void) stream;
784 
785     /* IMPLEMENT ME, see portaudio.h for required behavior*/
786 
787     return paNoError;
788 }
789 
790 
GetStreamReadAvailable(PaStream * s)791 static signed long GetStreamReadAvailable( PaStream* s )
792 {
793     PaSkeletonStream *stream = (PaSkeletonStream*)s;
794 
795     /* suppress unused variable warnings */
796     (void) stream;
797 
798     /* IMPLEMENT ME, see portaudio.h for required behavior*/
799 
800     return 0;
801 }
802 
803 
GetStreamWriteAvailable(PaStream * s)804 static signed long GetStreamWriteAvailable( PaStream* s )
805 {
806     PaSkeletonStream *stream = (PaSkeletonStream*)s;
807 
808     /* suppress unused variable warnings */
809     (void) stream;
810 
811     /* IMPLEMENT ME, see portaudio.h for required behavior*/
812 
813     return 0;
814 }
815 
816 
817 
818 
819