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