1 /*
2  * $Id$
3  * Portable Audio I/O Library Multi-Host API front end
4  * Validate function parameters and manage multiple host APIs.
5  *
6  * Based on the Open Source API proposed by Ross Bencina
7  * Copyright (c) 1999-2008 Ross Bencina, Phil Burk
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining
10  * a copy of this software and associated documentation files
11  * (the "Software"), to deal in the Software without restriction,
12  * including without limitation the rights to use, copy, modify, merge,
13  * publish, distribute, sublicense, and/or sell copies of the Software,
14  * and to permit persons to whom the Software is furnished to do so,
15  * subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
24  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
25  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27  */
28 
29 /*
30  * The text above constitutes the entire PortAudio license; however,
31  * the PortAudio community also makes the following non-binding requests:
32  *
33  * Any person wishing to distribute modifications to the Software is
34  * requested to send the modifications to the original developer so that
35  * they can be incorporated into the canonical version. It is also
36  * requested that these non-binding requests be included along with the
37  * license above.
38  */
39 
40 /** @file
41  @ingroup common_src
42 
43  @brief Implements PortAudio API functions defined in portaudio.h, checks
44  some errors, delegates platform-specific behavior to host API implementations.
45 
46  Implements the functions defined in the PortAudio API (portaudio.h),
47  validates some parameters and checks for state inconsistencies before
48  forwarding API requests to specific Host API implementations (via the
49  interface declared in pa_hostapi.h), and Streams (via the interface
50  declared in pa_stream.h).
51 
52  This file manages initialization and termination of Host API
53  implementations via initializer functions stored in the paHostApiInitializers
54  global array (usually defined in an os-specific pa_[os]_hostapis.c file).
55 
56  This file maintains a list of all open streams and closes them at Pa_Terminate().
57 
58  Some utility functions declared in pa_util.h are implemented in this file.
59 
60  All PortAudio API functions can be conditionally compiled with logging code.
61  To compile with logging, define the PA_LOG_API_CALLS precompiler symbol.
62 */
63 
64 
65 #include <stdio.h>
66 #include <memory.h>
67 #include <string.h>
68 #include <stdlib.h> /* needed for strtol() */
69 #include <assert.h> /* needed by PA_VALIDATE_ENDIANNESS */
70 
71 #include "portaudio.h"
72 #include "pa_util.h"
73 #include "pa_endianness.h"
74 #include "pa_types.h"
75 #include "pa_hostapi.h"
76 #include "pa_stream.h"
77 #include "pa_trace.h" /* still usefull?*/
78 #include "pa_debugprint.h"
79 
80 #ifndef PA_GIT_REVISION
81 #include "pa_gitrevision.h"
82 #endif
83 
84 /**
85  * This is incremented if we make incompatible API changes.
86  * This version scheme is based loosely on http://semver.org/
87  */
88 #define paVersionMajor     19
89 
90 /**
91  * This is incremented when we add functionality in a backwards-compatible manner.
92  * Or it is set to zero when paVersionMajor is incremented.
93  */
94 #define paVersionMinor      6
95 
96 /**
97  * This is incremented when we make backwards-compatible bug fixes.
98  * Or it is set to zero when paVersionMinor changes.
99  */
100 #define paVersionSubMinor   0
101 
102 /**
103  * This is a combination of paVersionMajor, paVersionMinor and paVersionSubMinor.
104  * It will always increase so that version numbers can be compared as integers to
105  * see which is later.
106  */
107 #define paVersion  paMakeVersionNumber(paVersionMajor, paVersionMinor, paVersionSubMinor)
108 
109 #define STRINGIFY(x) #x
110 #define TOSTRING(x) STRINGIFY(x)
111 
112 #define PA_VERSION_STRING_ TOSTRING(paVersionMajor) "." TOSTRING(paVersionMinor) "." TOSTRING(paVersionSubMinor)
113 #define PA_VERSION_TEXT_   "PortAudio V" PA_VERSION_STRING_ "-devel, revision " TOSTRING(PA_GIT_REVISION)
114 
Pa_GetVersion(void)115 int Pa_GetVersion( void )
116 {
117     return paVersion;
118 }
119 
Pa_GetVersionText(void)120 const char* Pa_GetVersionText( void )
121 {
122     return PA_VERSION_TEXT_;
123 }
124 
125 static PaVersionInfo versionInfo_ = {
126     /*.versionMajor =*/ paVersionMajor,
127     /*.versionMinor =*/ paVersionMinor,
128     /*.versionSubMinor =*/ paVersionSubMinor,
129     /*.versionControlRevision =*/ TOSTRING(PA_GIT_REVISION),
130     /*.versionText =*/ PA_VERSION_TEXT_
131 };
132 
Pa_GetVersionInfo()133 const PaVersionInfo* Pa_GetVersionInfo()
134 {
135     return &versionInfo_;
136 }
137 
138 #define PA_LAST_HOST_ERROR_TEXT_LENGTH_  1024
139 
140 static char lastHostErrorText_[ PA_LAST_HOST_ERROR_TEXT_LENGTH_ + 1 ] = {0};
141 
142 static PaHostErrorInfo lastHostErrorInfo_ = { (PaHostApiTypeId)-1, 0, lastHostErrorText_ };
143 
144 
PaUtil_SetLastHostErrorInfo(PaHostApiTypeId hostApiType,long errorCode,const char * errorText)145 void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode,
146         const char *errorText )
147 {
148     lastHostErrorInfo_.hostApiType = hostApiType;
149     lastHostErrorInfo_.errorCode = errorCode;
150 
151     strncpy( lastHostErrorText_, errorText, PA_LAST_HOST_ERROR_TEXT_LENGTH_ );
152 }
153 
154 
155 
156 static PaUtilHostApiRepresentation **hostApis_ = 0;
157 static int hostApisCount_ = 0;
158 static int defaultHostApiIndex_ = 0;
159 static int initializationCount_ = 0;
160 static int deviceCount_ = 0;
161 
162 PaUtilStreamRepresentation *firstOpenStream_ = NULL;
163 
164 
165 #define PA_IS_INITIALISED_ (initializationCount_ != 0)
166 
167 
CountHostApiInitializers(void)168 static int CountHostApiInitializers( void )
169 {
170     int result = 0;
171 
172     while( paHostApiInitializers[ result ] != 0 )
173         ++result;
174     return result;
175 }
176 
177 
TerminateHostApis(void)178 static void TerminateHostApis( void )
179 {
180     /* terminate in reverse order from initialization */
181     PA_DEBUG(("TerminateHostApis in \n"));
182 
183     while( hostApisCount_ > 0 )
184     {
185         --hostApisCount_;
186         hostApis_[hostApisCount_]->Terminate( hostApis_[hostApisCount_] );
187     }
188     hostApisCount_ = 0;
189     defaultHostApiIndex_ = 0;
190     deviceCount_ = 0;
191 
192     if( hostApis_ != 0 )
193         PaUtil_FreeMemory( hostApis_ );
194     hostApis_ = 0;
195 
196     PA_DEBUG(("TerminateHostApis out\n"));
197 }
198 
199 
InitializeHostApis(void)200 static PaError InitializeHostApis( void )
201 {
202     PaError result = paNoError;
203     int i, initializerCount, baseDeviceIndex;
204 
205     initializerCount = CountHostApiInitializers();
206 
207     hostApis_ = (PaUtilHostApiRepresentation**)PaUtil_AllocateMemory(
208             sizeof(PaUtilHostApiRepresentation*) * initializerCount );
209     if( !hostApis_ )
210     {
211         result = paInsufficientMemory;
212         goto error;
213     }
214 
215     hostApisCount_ = 0;
216     defaultHostApiIndex_ = -1; /* indicates that we haven't determined the default host API yet */
217     deviceCount_ = 0;
218     baseDeviceIndex = 0;
219 
220     for( i=0; i< initializerCount; ++i )
221     {
222         hostApis_[hostApisCount_] = NULL;
223 
224         PA_DEBUG(( "before paHostApiInitializers[%d].\n",i));
225 
226         result = paHostApiInitializers[i]( &hostApis_[hostApisCount_], hostApisCount_ );
227         if( result != paNoError )
228             goto error;
229 
230         PA_DEBUG(( "after paHostApiInitializers[%d].\n",i));
231 
232         if( hostApis_[hostApisCount_] )
233         {
234             PaUtilHostApiRepresentation* hostApi = hostApis_[hostApisCount_];
235             assert( hostApi->info.defaultInputDevice < hostApi->info.deviceCount );
236             assert( hostApi->info.defaultOutputDevice < hostApi->info.deviceCount );
237 
238             /* the first successfully initialized host API with a default input *or*
239                output device is used as the default host API.
240             */
241             if( (defaultHostApiIndex_ == -1) &&
242                     ( hostApi->info.defaultInputDevice != paNoDevice
243                         || hostApi->info.defaultOutputDevice != paNoDevice ) )
244             {
245                 defaultHostApiIndex_ = hostApisCount_;
246             }
247 
248             hostApi->privatePaFrontInfo.baseDeviceIndex = baseDeviceIndex;
249 
250             if( hostApi->info.defaultInputDevice != paNoDevice )
251                 hostApi->info.defaultInputDevice += baseDeviceIndex;
252 
253             if( hostApi->info.defaultOutputDevice != paNoDevice )
254                 hostApi->info.defaultOutputDevice += baseDeviceIndex;
255 
256             baseDeviceIndex += hostApi->info.deviceCount;
257             deviceCount_ += hostApi->info.deviceCount;
258 
259             ++hostApisCount_;
260         }
261     }
262 
263     /* if no host APIs have devices, the default host API is the first initialized host API */
264     if( defaultHostApiIndex_ == -1 )
265         defaultHostApiIndex_ = 0;
266 
267     return result;
268 
269 error:
270     TerminateHostApis();
271     return result;
272 }
273 
274 
275 /*
276     FindHostApi() finds the index of the host api to which
277     <device> belongs and returns it. if <hostSpecificDeviceIndex> is
278     non-null, the host specific device index is returned in it.
279     returns -1 if <device> is out of range.
280 
281 */
FindHostApi(PaDeviceIndex device,int * hostSpecificDeviceIndex)282 static int FindHostApi( PaDeviceIndex device, int *hostSpecificDeviceIndex )
283 {
284     int i=0;
285 
286     if( !PA_IS_INITIALISED_ )
287         return -1;
288 
289     if( device < 0 )
290         return -1;
291 
292     while( i < hostApisCount_
293             && device >= hostApis_[i]->info.deviceCount )
294     {
295 
296         device -= hostApis_[i]->info.deviceCount;
297         ++i;
298     }
299 
300     if( i >= hostApisCount_ )
301         return -1;
302 
303     if( hostSpecificDeviceIndex )
304         *hostSpecificDeviceIndex = device;
305 
306     return i;
307 }
308 
309 
AddOpenStream(PaStream * stream)310 static void AddOpenStream( PaStream* stream )
311 {
312     ((PaUtilStreamRepresentation*)stream)->nextOpenStream = firstOpenStream_;
313     firstOpenStream_ = (PaUtilStreamRepresentation*)stream;
314 }
315 
316 
RemoveOpenStream(PaStream * stream)317 static void RemoveOpenStream( PaStream* stream )
318 {
319     PaUtilStreamRepresentation *previous = NULL;
320     PaUtilStreamRepresentation *current = firstOpenStream_;
321 
322     while( current != NULL )
323     {
324         if( ((PaStream*)current) == stream )
325         {
326             if( previous == NULL )
327             {
328                 firstOpenStream_ = current->nextOpenStream;
329             }
330             else
331             {
332                 previous->nextOpenStream = current->nextOpenStream;
333             }
334             return;
335         }
336         else
337         {
338             previous = current;
339             current = current->nextOpenStream;
340         }
341     }
342 }
343 
344 
CloseOpenStreams(void)345 static void CloseOpenStreams( void )
346 {
347     /* we call Pa_CloseStream() here to ensure that the same destruction
348         logic is used for automatically closed streams */
349 
350     while( firstOpenStream_ != NULL )
351         Pa_CloseStream( firstOpenStream_ );
352 }
353 
354 
Pa_Initialize(void)355 PaError Pa_Initialize( void )
356 {
357     PaError result;
358 
359     PA_LOGAPI_ENTER( "Pa_Initialize" );
360 
361     if( PA_IS_INITIALISED_ )
362     {
363         ++initializationCount_;
364         result = paNoError;
365     }
366     else
367     {
368         PA_VALIDATE_TYPE_SIZES;
369         PA_VALIDATE_ENDIANNESS;
370 
371         PaUtil_InitializeClock();
372         PaUtil_ResetTraceMessages();
373 
374         result = InitializeHostApis();
375         if( result == paNoError )
376             ++initializationCount_;
377     }
378 
379     PA_LOGAPI_EXIT_PAERROR( "Pa_Initialize", result );
380 
381     return result;
382 }
383 
384 
Pa_Terminate(void)385 PaError Pa_Terminate( void )
386 {
387     PaError result;
388 
389     PA_LOGAPI_ENTER( "Pa_Terminate" );
390 
391     if( PA_IS_INITIALISED_ )
392     {
393         // leave initializationCount_>0 so that Pa_CloseStream() can execute
394         if( initializationCount_ == 1 )
395         {
396             CloseOpenStreams();
397 
398             TerminateHostApis();
399 
400             PaUtil_DumpTraceMessages();
401         }
402         --initializationCount_;
403         result = paNoError;
404     }
405     else
406     {
407         result=  paNotInitialized;
408     }
409 
410     PA_LOGAPI_EXIT_PAERROR( "Pa_Terminate", result );
411 
412     return result;
413 }
414 
415 
Pa_GetLastHostErrorInfo(void)416 const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void )
417 {
418     return &lastHostErrorInfo_;
419 }
420 
421 
Pa_GetErrorText(PaError errorCode)422 const char *Pa_GetErrorText( PaError errorCode )
423 {
424     const char *result;
425 
426     switch( errorCode )
427     {
428     case paNoError:                  result = "Success"; break;
429     case paNotInitialized:           result = "PortAudio not initialized"; break;
430     /** @todo could catenate the last host error text to result in the case of paUnanticipatedHostError. see: http://www.portaudio.com/trac/ticket/114 */
431     case paUnanticipatedHostError:   result = "Unanticipated host error"; break;
432     case paInvalidChannelCount:      result = "Invalid number of channels"; break;
433     case paInvalidSampleRate:        result = "Invalid sample rate"; break;
434     case paInvalidDevice:            result = "Invalid device"; break;
435     case paInvalidFlag:              result = "Invalid flag"; break;
436     case paSampleFormatNotSupported: result = "Sample format not supported"; break;
437     case paBadIODeviceCombination:   result = "Illegal combination of I/O devices"; break;
438     case paInsufficientMemory:       result = "Insufficient memory"; break;
439     case paBufferTooBig:             result = "Buffer too big"; break;
440     case paBufferTooSmall:           result = "Buffer too small"; break;
441     case paNullCallback:             result = "No callback routine specified"; break;
442     case paBadStreamPtr:             result = "Invalid stream pointer"; break;
443     case paTimedOut:                 result = "Wait timed out"; break;
444     case paInternalError:            result = "Internal PortAudio error"; break;
445     case paDeviceUnavailable:        result = "Device unavailable"; break;
446     case paIncompatibleHostApiSpecificStreamInfo:   result = "Incompatible host API specific stream info"; break;
447     case paStreamIsStopped:          result = "Stream is stopped"; break;
448     case paStreamIsNotStopped:       result = "Stream is not stopped"; break;
449     case paInputOverflowed:          result = "Input overflowed"; break;
450     case paOutputUnderflowed:        result = "Output underflowed"; break;
451     case paHostApiNotFound:          result = "Host API not found"; break;
452     case paInvalidHostApi:           result = "Invalid host API"; break;
453     case paCanNotReadFromACallbackStream:       result = "Can't read from a callback stream"; break;
454     case paCanNotWriteToACallbackStream:        result = "Can't write to a callback stream"; break;
455     case paCanNotReadFromAnOutputOnlyStream:    result = "Can't read from an output only stream"; break;
456     case paCanNotWriteToAnInputOnlyStream:      result = "Can't write to an input only stream"; break;
457     case paIncompatibleStreamHostApi: result = "Incompatible stream host API"; break;
458     case paBadBufferPtr:             result = "Bad buffer pointer"; break;
459     default:
460 		if( errorCode > 0 )
461 			result = "Invalid error code (value greater than zero)";
462         else
463 			result = "Invalid error code";
464         break;
465     }
466     return result;
467 }
468 
469 
Pa_HostApiTypeIdToHostApiIndex(PaHostApiTypeId type)470 PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type )
471 {
472     PaHostApiIndex result;
473     int i;
474 
475     PA_LOGAPI_ENTER_PARAMS( "Pa_HostApiTypeIdToHostApiIndex" );
476     PA_LOGAPI(("\tPaHostApiTypeId type: %d\n", type ));
477 
478     if( !PA_IS_INITIALISED_ )
479     {
480         result = paNotInitialized;
481     }
482     else
483     {
484         result = paHostApiNotFound;
485 
486         for( i=0; i < hostApisCount_; ++i )
487         {
488             if( hostApis_[i]->info.type == type )
489             {
490                 result = i;
491                 break;
492             }
493         }
494     }
495 
496     PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_HostApiTypeIdToHostApiIndex", "PaHostApiIndex: %d", result );
497 
498     return result;
499 }
500 
501 
PaUtil_GetHostApiRepresentation(struct PaUtilHostApiRepresentation ** hostApi,PaHostApiTypeId type)502 PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi,
503         PaHostApiTypeId type )
504 {
505     PaError result;
506     int i;
507 
508     if( !PA_IS_INITIALISED_ )
509     {
510         result = paNotInitialized;
511     }
512     else
513     {
514         result = paHostApiNotFound;
515 
516         for( i=0; i < hostApisCount_; ++i )
517         {
518             if( hostApis_[i]->info.type == type )
519             {
520                 *hostApi = hostApis_[i];
521                 result = paNoError;
522                 break;
523             }
524         }
525     }
526 
527     return result;
528 }
529 
530 
PaUtil_DeviceIndexToHostApiDeviceIndex(PaDeviceIndex * hostApiDevice,PaDeviceIndex device,struct PaUtilHostApiRepresentation * hostApi)531 PaError PaUtil_DeviceIndexToHostApiDeviceIndex(
532         PaDeviceIndex *hostApiDevice, PaDeviceIndex device, struct PaUtilHostApiRepresentation *hostApi )
533 {
534     PaError result;
535     PaDeviceIndex x;
536 
537     x = device - hostApi->privatePaFrontInfo.baseDeviceIndex;
538 
539     if( x < 0 || x >= hostApi->info.deviceCount )
540     {
541         result = paInvalidDevice;
542     }
543     else
544     {
545         *hostApiDevice = x;
546         result = paNoError;
547     }
548 
549     return result;
550 }
551 
552 
Pa_GetHostApiCount(void)553 PaHostApiIndex Pa_GetHostApiCount( void )
554 {
555     int result;
556 
557     PA_LOGAPI_ENTER( "Pa_GetHostApiCount" );
558 
559     if( !PA_IS_INITIALISED_ )
560     {
561         result = paNotInitialized;
562     }
563     else
564     {
565         result = hostApisCount_;
566     }
567 
568     PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_GetHostApiCount", "PaHostApiIndex: %d", result );
569 
570     return result;
571 }
572 
573 
Pa_GetDefaultHostApi(void)574 PaHostApiIndex Pa_GetDefaultHostApi( void )
575 {
576     int result;
577 
578     PA_LOGAPI_ENTER( "Pa_GetDefaultHostApi" );
579 
580     if( !PA_IS_INITIALISED_ )
581     {
582         result = paNotInitialized;
583     }
584     else
585     {
586         result = defaultHostApiIndex_;
587 
588         /* internal consistency check: make sure that the default host api
589          index is within range */
590 
591         if( result < 0 || result >= hostApisCount_ )
592         {
593             result = paInternalError;
594         }
595     }
596 
597     PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_GetDefaultHostApi", "PaHostApiIndex: %d", result );
598 
599     return result;
600 }
601 
602 
Pa_GetHostApiInfo(PaHostApiIndex hostApi)603 const PaHostApiInfo* Pa_GetHostApiInfo( PaHostApiIndex hostApi )
604 {
605     PaHostApiInfo *info;
606 
607     PA_LOGAPI_ENTER_PARAMS( "Pa_GetHostApiInfo" );
608     PA_LOGAPI(("\tPaHostApiIndex hostApi: %d\n", hostApi ));
609 
610     if( !PA_IS_INITIALISED_ )
611     {
612         info = NULL;
613 
614         PA_LOGAPI(("Pa_GetHostApiInfo returned:\n" ));
615         PA_LOGAPI(("\tPaHostApiInfo*: NULL [ PortAudio not initialized ]\n" ));
616 
617     }
618     else if( hostApi < 0 || hostApi >= hostApisCount_ )
619     {
620         info = NULL;
621 
622         PA_LOGAPI(("Pa_GetHostApiInfo returned:\n" ));
623         PA_LOGAPI(("\tPaHostApiInfo*: NULL [ hostApi out of range ]\n" ));
624 
625     }
626     else
627     {
628         info = &hostApis_[hostApi]->info;
629 
630         PA_LOGAPI(("Pa_GetHostApiInfo returned:\n" ));
631         PA_LOGAPI(("\tPaHostApiInfo*: 0x%p\n", info ));
632         PA_LOGAPI(("\t{\n" ));
633         PA_LOGAPI(("\t\tint structVersion: %d\n", info->structVersion ));
634         PA_LOGAPI(("\t\tPaHostApiTypeId type: %d\n", info->type ));
635         PA_LOGAPI(("\t\tconst char *name: %s\n", info->name ));
636         PA_LOGAPI(("\t}\n" ));
637 
638     }
639 
640      return info;
641 }
642 
643 
Pa_HostApiDeviceIndexToDeviceIndex(PaHostApiIndex hostApi,int hostApiDeviceIndex)644 PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, int hostApiDeviceIndex )
645 {
646     PaDeviceIndex result;
647 
648     PA_LOGAPI_ENTER_PARAMS( "Pa_HostApiDeviceIndexToPaDeviceIndex" );
649     PA_LOGAPI(("\tPaHostApiIndex hostApi: %d\n", hostApi ));
650     PA_LOGAPI(("\tint hostApiDeviceIndex: %d\n", hostApiDeviceIndex ));
651 
652     if( !PA_IS_INITIALISED_ )
653     {
654         result = paNotInitialized;
655     }
656     else
657     {
658         if( hostApi < 0 || hostApi >= hostApisCount_ )
659         {
660             result = paInvalidHostApi;
661         }
662         else
663         {
664             if( hostApiDeviceIndex < 0 ||
665                     hostApiDeviceIndex >= hostApis_[hostApi]->info.deviceCount )
666             {
667                 result = paInvalidDevice;
668             }
669             else
670             {
671                 result = hostApis_[hostApi]->privatePaFrontInfo.baseDeviceIndex + hostApiDeviceIndex;
672             }
673         }
674     }
675 
676     PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_HostApiDeviceIndexToPaDeviceIndex", "PaDeviceIndex: %d", result );
677 
678     return result;
679 }
680 
681 
Pa_GetDeviceCount(void)682 PaDeviceIndex Pa_GetDeviceCount( void )
683 {
684     PaDeviceIndex result;
685 
686     PA_LOGAPI_ENTER( "Pa_GetDeviceCount" );
687 
688     if( !PA_IS_INITIALISED_ )
689     {
690         result = paNotInitialized;
691     }
692     else
693     {
694         result = deviceCount_;
695     }
696 
697     PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_GetDeviceCount", "PaDeviceIndex: %d", result );
698 
699     return result;
700 }
701 
702 
Pa_GetDefaultInputDevice(void)703 PaDeviceIndex Pa_GetDefaultInputDevice( void )
704 {
705     PaHostApiIndex hostApi;
706     PaDeviceIndex result;
707 
708     PA_LOGAPI_ENTER( "Pa_GetDefaultInputDevice" );
709 
710     hostApi = Pa_GetDefaultHostApi();
711     if( hostApi < 0 )
712     {
713         result = paNoDevice;
714     }
715     else
716     {
717         result = hostApis_[hostApi]->info.defaultInputDevice;
718     }
719 
720     PA_LOGAPI_EXIT_T( "Pa_GetDefaultInputDevice", "PaDeviceIndex: %d", result );
721 
722     return result;
723 }
724 
725 
Pa_GetDefaultOutputDevice(void)726 PaDeviceIndex Pa_GetDefaultOutputDevice( void )
727 {
728     PaHostApiIndex hostApi;
729     PaDeviceIndex result;
730 
731     PA_LOGAPI_ENTER( "Pa_GetDefaultOutputDevice" );
732 
733     hostApi = Pa_GetDefaultHostApi();
734     if( hostApi < 0 )
735     {
736         result = paNoDevice;
737     }
738     else
739     {
740         result = hostApis_[hostApi]->info.defaultOutputDevice;
741     }
742 
743     PA_LOGAPI_EXIT_T( "Pa_GetDefaultOutputDevice", "PaDeviceIndex: %d", result );
744 
745     return result;
746 }
747 
748 
Pa_GetDeviceInfo(PaDeviceIndex device)749 const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device )
750 {
751     int hostSpecificDeviceIndex;
752     int hostApiIndex = FindHostApi( device, &hostSpecificDeviceIndex );
753     PaDeviceInfo *result;
754 
755 
756     PA_LOGAPI_ENTER_PARAMS( "Pa_GetDeviceInfo" );
757     PA_LOGAPI(("\tPaDeviceIndex device: %d\n", device ));
758 
759     if( hostApiIndex < 0 )
760     {
761         result = NULL;
762 
763         PA_LOGAPI(("Pa_GetDeviceInfo returned:\n" ));
764         PA_LOGAPI(("\tPaDeviceInfo* NULL [ invalid device index ]\n" ));
765 
766     }
767     else
768     {
769         result = hostApis_[hostApiIndex]->deviceInfos[ hostSpecificDeviceIndex ];
770 
771         PA_LOGAPI(("Pa_GetDeviceInfo returned:\n" ));
772         PA_LOGAPI(("\tPaDeviceInfo*: 0x%p:\n", result ));
773         PA_LOGAPI(("\t{\n" ));
774 
775         PA_LOGAPI(("\t\tint structVersion: %d\n", result->structVersion ));
776         PA_LOGAPI(("\t\tconst char *name: %s\n", result->name ));
777         PA_LOGAPI(("\t\tPaHostApiIndex hostApi: %d\n", result->hostApi ));
778         PA_LOGAPI(("\t\tint maxInputChannels: %d\n", result->maxInputChannels ));
779         PA_LOGAPI(("\t\tint maxOutputChannels: %d\n", result->maxOutputChannels ));
780         PA_LOGAPI(("\t}\n" ));
781 
782     }
783 
784     return result;
785 }
786 
787 
788 /*
789     SampleFormatIsValid() returns 1 if sampleFormat is a sample format
790     defined in portaudio.h, or 0 otherwise.
791 */
SampleFormatIsValid(PaSampleFormat format)792 static int SampleFormatIsValid( PaSampleFormat format )
793 {
794     switch( format & ~paNonInterleaved )
795     {
796     case paFloat32: return 1;
797     case paInt16: return 1;
798     case paInt32: return 1;
799     case paInt24: return 1;
800     case paInt8: return 1;
801     case paUInt8: return 1;
802     case paCustomFormat: return 1;
803     default: return 0;
804     }
805 }
806 
807 /*
808     NOTE: make sure this validation list is kept syncronised with the one in
809             pa_hostapi.h
810 
811     ValidateOpenStreamParameters() checks that parameters to Pa_OpenStream()
812     conform to the expected values as described below. This function is
813     also designed to be used with the proposed Pa_IsFormatSupported() function.
814 
815     There are basically two types of validation that could be performed:
816     Generic conformance validation, and device capability mismatch
817     validation. This function performs only generic conformance validation.
818     Validation that would require knowledge of device capabilities is
819     not performed because of potentially complex relationships between
820     combinations of parameters - for example, even if the sampleRate
821     seems ok, it might not be for a duplex stream - we have no way of
822     checking this in an API-neutral way, so we don't try.
823 
824     On success the function returns PaNoError and fills in hostApi,
825     hostApiInputDeviceID, and hostApiOutputDeviceID fields. On failure
826     the function returns an error code indicating the first encountered
827     parameter error.
828 
829 
830     If ValidateOpenStreamParameters() returns paNoError, the following
831     assertions are guaranteed to be true.
832 
833     - at least one of inputParameters & outputParmeters is valid (not NULL)
834 
835     - if inputParameters & outputParameters are both valid, that
836         inputParameters->device & outputParameters->device  both use the same host api
837 
838     PaDeviceIndex inputParameters->device
839         - is within range (0 to Pa_GetDeviceCount-1) Or:
840         - is paUseHostApiSpecificDeviceSpecification and
841             inputParameters->hostApiSpecificStreamInfo is non-NULL and refers
842             to a valid host api
843 
844     int inputParameters->channelCount
845         - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, channelCount is > 0
846         - upper bound is NOT validated against device capabilities
847 
848     PaSampleFormat inputParameters->sampleFormat
849         - is one of the sample formats defined in portaudio.h
850 
851     void *inputParameters->hostApiSpecificStreamInfo
852         - if supplied its hostApi field matches the input device's host Api
853 
854     PaDeviceIndex outputParmeters->device
855         - is within range (0 to Pa_GetDeviceCount-1)
856 
857     int outputParmeters->channelCount
858         - if inputDevice is valid, channelCount is > 0
859         - upper bound is NOT validated against device capabilities
860 
861     PaSampleFormat outputParmeters->sampleFormat
862         - is one of the sample formats defined in portaudio.h
863 
864     void *outputParmeters->hostApiSpecificStreamInfo
865         - if supplied its hostApi field matches the output device's host Api
866 
867     double sampleRate
868         - is not an 'absurd' rate (less than 1000. or greater than 384000.)
869         - sampleRate is NOT validated against device capabilities
870 
871     PaStreamFlags streamFlags
872         - unused platform neutral flags are zero
873         - paNeverDropInput is only used for full-duplex callback streams with
874             variable buffer size (paFramesPerBufferUnspecified)
875 */
ValidateOpenStreamParameters(const PaStreamParameters * inputParameters,const PaStreamParameters * outputParameters,double sampleRate,unsigned long framesPerBuffer,PaStreamFlags streamFlags,PaStreamCallback * streamCallback,PaUtilHostApiRepresentation ** hostApi,PaDeviceIndex * hostApiInputDevice,PaDeviceIndex * hostApiOutputDevice)876 static PaError ValidateOpenStreamParameters(
877     const PaStreamParameters *inputParameters,
878     const PaStreamParameters *outputParameters,
879     double sampleRate,
880     unsigned long framesPerBuffer,
881     PaStreamFlags streamFlags,
882     PaStreamCallback *streamCallback,
883     PaUtilHostApiRepresentation **hostApi,
884     PaDeviceIndex *hostApiInputDevice,
885     PaDeviceIndex *hostApiOutputDevice )
886 {
887     int inputHostApiIndex  = -1, /* Surpress uninitialised var warnings: compiler does */
888         outputHostApiIndex = -1; /* not see that if inputParameters and outputParame-  */
889                                  /* ters are both nonzero, these indices are set.      */
890 
891     if( (inputParameters == NULL) && (outputParameters == NULL) )
892     {
893         return paInvalidDevice; /** @todo should be a new error code "invalid device parameters" or something */
894     }
895     else
896     {
897         if( inputParameters == NULL )
898         {
899             *hostApiInputDevice = paNoDevice;
900         }
901         else if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
902         {
903             if( inputParameters->hostApiSpecificStreamInfo )
904             {
905                 inputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex(
906                         ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType );
907 
908                 if( inputHostApiIndex != -1 )
909                 {
910                     *hostApiInputDevice = paUseHostApiSpecificDeviceSpecification;
911                     *hostApi = hostApis_[inputHostApiIndex];
912                 }
913                 else
914                 {
915                     return paInvalidDevice;
916                 }
917             }
918             else
919             {
920                 return paInvalidDevice;
921             }
922         }
923         else
924         {
925             if( inputParameters->device < 0 || inputParameters->device >= deviceCount_ )
926                 return paInvalidDevice;
927 
928             inputHostApiIndex = FindHostApi( inputParameters->device, hostApiInputDevice );
929             if( inputHostApiIndex < 0 )
930                 return paInternalError;
931 
932             *hostApi = hostApis_[inputHostApiIndex];
933 
934             if( inputParameters->channelCount <= 0 )
935                 return paInvalidChannelCount;
936 
937             if( !SampleFormatIsValid( inputParameters->sampleFormat ) )
938                 return paSampleFormatNotSupported;
939 
940             if( inputParameters->hostApiSpecificStreamInfo != NULL )
941             {
942                 if( ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType
943                         != (*hostApi)->info.type )
944                     return paIncompatibleHostApiSpecificStreamInfo;
945             }
946         }
947 
948         if( outputParameters == NULL )
949         {
950             *hostApiOutputDevice = paNoDevice;
951         }
952         else if( outputParameters->device == paUseHostApiSpecificDeviceSpecification  )
953         {
954             if( outputParameters->hostApiSpecificStreamInfo )
955             {
956                 outputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex(
957                         ((PaUtilHostApiSpecificStreamInfoHeader*)outputParameters->hostApiSpecificStreamInfo)->hostApiType );
958 
959                 if( outputHostApiIndex != -1 )
960                 {
961                     *hostApiOutputDevice = paUseHostApiSpecificDeviceSpecification;
962                     *hostApi = hostApis_[outputHostApiIndex];
963                 }
964                 else
965                 {
966                     return paInvalidDevice;
967                 }
968             }
969             else
970             {
971                 return paInvalidDevice;
972             }
973         }
974         else
975         {
976             if( outputParameters->device < 0 || outputParameters->device >= deviceCount_ )
977                 return paInvalidDevice;
978 
979             outputHostApiIndex = FindHostApi( outputParameters->device, hostApiOutputDevice );
980             if( outputHostApiIndex < 0 )
981                 return paInternalError;
982 
983             *hostApi = hostApis_[outputHostApiIndex];
984 
985             if( outputParameters->channelCount <= 0 )
986                 return paInvalidChannelCount;
987 
988             if( !SampleFormatIsValid( outputParameters->sampleFormat ) )
989                 return paSampleFormatNotSupported;
990 
991             if( outputParameters->hostApiSpecificStreamInfo != NULL )
992             {
993                 if( ((PaUtilHostApiSpecificStreamInfoHeader*)outputParameters->hostApiSpecificStreamInfo)->hostApiType
994                         != (*hostApi)->info.type )
995                     return paIncompatibleHostApiSpecificStreamInfo;
996             }
997         }
998 
999         if( (inputParameters != NULL) && (outputParameters != NULL) )
1000         {
1001             /* ensure that both devices use the same API */
1002             if( inputHostApiIndex != outputHostApiIndex )
1003                 return paBadIODeviceCombination;
1004         }
1005     }
1006 
1007 
1008     /* Check for absurd sample rates. */
1009     if( (sampleRate < 1000.0) || (sampleRate > 384000.0) )
1010         return paInvalidSampleRate;
1011 
1012     if( ((streamFlags & ~paPlatformSpecificFlags) & ~(paClipOff | paDitherOff | paNeverDropInput | paPrimeOutputBuffersUsingStreamCallback ) ) != 0 )
1013         return paInvalidFlag;
1014 
1015     if( streamFlags & paNeverDropInput )
1016     {
1017         /* must be a callback stream */
1018         if( !streamCallback )
1019              return paInvalidFlag;
1020 
1021         /* must be a full duplex stream */
1022         if( (inputParameters == NULL) || (outputParameters == NULL) )
1023             return paInvalidFlag;
1024 
1025         /* must use paFramesPerBufferUnspecified */
1026         if( framesPerBuffer != paFramesPerBufferUnspecified )
1027             return paInvalidFlag;
1028     }
1029 
1030     return paNoError;
1031 }
1032 
1033 
Pa_IsFormatSupported(const PaStreamParameters * inputParameters,const PaStreamParameters * outputParameters,double sampleRate)1034 PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters,
1035                               const PaStreamParameters *outputParameters,
1036                               double sampleRate )
1037 {
1038     PaError result;
1039     PaUtilHostApiRepresentation *hostApi = 0;
1040     PaDeviceIndex hostApiInputDevice = paNoDevice, hostApiOutputDevice = paNoDevice;
1041     PaStreamParameters hostApiInputParameters, hostApiOutputParameters;
1042     PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;
1043 
1044 
1045 #ifdef PA_LOG_API_CALLS
1046     PA_LOGAPI_ENTER_PARAMS( "Pa_IsFormatSupported" );
1047 
1048     if( inputParameters == NULL ){
1049         PA_LOGAPI(("\tPaStreamParameters *inputParameters: NULL\n" ));
1050     }else{
1051         PA_LOGAPI(("\tPaStreamParameters *inputParameters: 0x%p\n", inputParameters ));
1052         PA_LOGAPI(("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device ));
1053         PA_LOGAPI(("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount ));
1054         PA_LOGAPI(("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat ));
1055         PA_LOGAPI(("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency ));
1056         PA_LOGAPI(("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo ));
1057     }
1058 
1059     if( outputParameters == NULL ){
1060         PA_LOGAPI(("\tPaStreamParameters *outputParameters: NULL\n" ));
1061     }else{
1062         PA_LOGAPI(("\tPaStreamParameters *outputParameters: 0x%p\n", outputParameters ));
1063         PA_LOGAPI(("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device ));
1064         PA_LOGAPI(("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount ));
1065         PA_LOGAPI(("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat ));
1066         PA_LOGAPI(("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency ));
1067         PA_LOGAPI(("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo ));
1068     }
1069 
1070     PA_LOGAPI(("\tdouble sampleRate: %g\n", sampleRate ));
1071 #endif
1072 
1073     if( !PA_IS_INITIALISED_ )
1074     {
1075         result = paNotInitialized;
1076 
1077         PA_LOGAPI_EXIT_PAERROR( "Pa_IsFormatSupported", result );
1078         return result;
1079     }
1080 
1081     result = ValidateOpenStreamParameters( inputParameters,
1082                                            outputParameters,
1083                                            sampleRate, 0, paNoFlag, 0,
1084                                            &hostApi,
1085                                            &hostApiInputDevice,
1086                                            &hostApiOutputDevice );
1087     if( result != paNoError )
1088     {
1089         PA_LOGAPI_EXIT_PAERROR( "Pa_IsFormatSupported", result );
1090         return result;
1091     }
1092 
1093 
1094     if( inputParameters )
1095     {
1096         hostApiInputParameters.device = hostApiInputDevice;
1097         hostApiInputParameters.channelCount = inputParameters->channelCount;
1098         hostApiInputParameters.sampleFormat = inputParameters->sampleFormat;
1099         hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency;
1100         hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo;
1101         hostApiInputParametersPtr = &hostApiInputParameters;
1102     }
1103     else
1104     {
1105         hostApiInputParametersPtr = NULL;
1106     }
1107 
1108     if( outputParameters )
1109     {
1110         hostApiOutputParameters.device = hostApiOutputDevice;
1111         hostApiOutputParameters.channelCount = outputParameters->channelCount;
1112         hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat;
1113         hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency;
1114         hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo;
1115         hostApiOutputParametersPtr = &hostApiOutputParameters;
1116     }
1117     else
1118     {
1119         hostApiOutputParametersPtr = NULL;
1120     }
1121 
1122     result = hostApi->IsFormatSupported( hostApi,
1123                                   hostApiInputParametersPtr, hostApiOutputParametersPtr,
1124                                   sampleRate );
1125 
1126 #ifdef PA_LOG_API_CALLS
1127     PA_LOGAPI(("Pa_OpenStream returned:\n" ));
1128     if( result == paFormatIsSupported )
1129         PA_LOGAPI(("\tPaError: 0 [ paFormatIsSupported ]\n" ));
1130     else
1131         PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ));
1132 #endif
1133 
1134     return result;
1135 }
1136 
1137 
Pa_OpenStream(PaStream ** stream,const PaStreamParameters * inputParameters,const PaStreamParameters * outputParameters,double sampleRate,unsigned long framesPerBuffer,PaStreamFlags streamFlags,PaStreamCallback * streamCallback,void * userData)1138 PaError Pa_OpenStream( PaStream** stream,
1139                        const PaStreamParameters *inputParameters,
1140                        const PaStreamParameters *outputParameters,
1141                        double sampleRate,
1142                        unsigned long framesPerBuffer,
1143                        PaStreamFlags streamFlags,
1144                        PaStreamCallback *streamCallback,
1145                        void *userData )
1146 {
1147     PaError result;
1148     PaUtilHostApiRepresentation *hostApi = 0;
1149     PaDeviceIndex hostApiInputDevice = paNoDevice, hostApiOutputDevice = paNoDevice;
1150     PaStreamParameters hostApiInputParameters, hostApiOutputParameters;
1151     PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;
1152 
1153 
1154 #ifdef PA_LOG_API_CALLS
1155     PA_LOGAPI_ENTER_PARAMS( "Pa_OpenStream" );
1156     PA_LOGAPI(("\tPaStream** stream: 0x%p\n", stream ));
1157 
1158     if( inputParameters == NULL ){
1159         PA_LOGAPI(("\tPaStreamParameters *inputParameters: NULL\n" ));
1160     }else{
1161         PA_LOGAPI(("\tPaStreamParameters *inputParameters: 0x%p\n", inputParameters ));
1162         PA_LOGAPI(("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device ));
1163         PA_LOGAPI(("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount ));
1164         PA_LOGAPI(("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat ));
1165         PA_LOGAPI(("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency ));
1166         PA_LOGAPI(("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo ));
1167     }
1168 
1169     if( outputParameters == NULL ){
1170         PA_LOGAPI(("\tPaStreamParameters *outputParameters: NULL\n" ));
1171     }else{
1172         PA_LOGAPI(("\tPaStreamParameters *outputParameters: 0x%p\n", outputParameters ));
1173         PA_LOGAPI(("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device ));
1174         PA_LOGAPI(("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount ));
1175         PA_LOGAPI(("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat ));
1176         PA_LOGAPI(("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency ));
1177         PA_LOGAPI(("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo ));
1178     }
1179 
1180     PA_LOGAPI(("\tdouble sampleRate: %g\n", sampleRate ));
1181     PA_LOGAPI(("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer ));
1182     PA_LOGAPI(("\tPaStreamFlags streamFlags: 0x%x\n", streamFlags ));
1183     PA_LOGAPI(("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback ));
1184     PA_LOGAPI(("\tvoid *userData: 0x%p\n", userData ));
1185 #endif
1186 
1187     if( !PA_IS_INITIALISED_ )
1188     {
1189         result = paNotInitialized;
1190 
1191         PA_LOGAPI(("Pa_OpenStream returned:\n" ));
1192         PA_LOGAPI(("\t*(PaStream** stream): undefined\n" ));
1193         PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ));
1194         return result;
1195     }
1196 
1197     /* Check for parameter errors.
1198         NOTE: make sure this validation list is kept syncronised with the one
1199         in pa_hostapi.h
1200     */
1201 
1202     if( stream == NULL )
1203     {
1204         result = paBadStreamPtr;
1205 
1206         PA_LOGAPI(("Pa_OpenStream returned:\n" ));
1207         PA_LOGAPI(("\t*(PaStream** stream): undefined\n" ));
1208         PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ));
1209         return result;
1210     }
1211 
1212     result = ValidateOpenStreamParameters( inputParameters,
1213                                            outputParameters,
1214                                            sampleRate, framesPerBuffer,
1215                                            streamFlags, streamCallback,
1216                                            &hostApi,
1217                                            &hostApiInputDevice,
1218                                            &hostApiOutputDevice );
1219     if( result != paNoError )
1220     {
1221         PA_LOGAPI(("Pa_OpenStream returned:\n" ));
1222         PA_LOGAPI(("\t*(PaStream** stream): undefined\n" ));
1223         PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ));
1224         return result;
1225     }
1226 
1227 
1228     if( inputParameters )
1229     {
1230         hostApiInputParameters.device = hostApiInputDevice;
1231         hostApiInputParameters.channelCount = inputParameters->channelCount;
1232         hostApiInputParameters.sampleFormat = inputParameters->sampleFormat;
1233         hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency;
1234         hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo;
1235         hostApiInputParametersPtr = &hostApiInputParameters;
1236     }
1237     else
1238     {
1239         hostApiInputParametersPtr = NULL;
1240     }
1241 
1242     if( outputParameters )
1243     {
1244         hostApiOutputParameters.device = hostApiOutputDevice;
1245         hostApiOutputParameters.channelCount = outputParameters->channelCount;
1246         hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat;
1247         hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency;
1248         hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo;
1249         hostApiOutputParametersPtr = &hostApiOutputParameters;
1250     }
1251     else
1252     {
1253         hostApiOutputParametersPtr = NULL;
1254     }
1255 
1256     result = hostApi->OpenStream( hostApi, stream,
1257                                   hostApiInputParametersPtr, hostApiOutputParametersPtr,
1258                                   sampleRate, framesPerBuffer, streamFlags, streamCallback, userData );
1259 
1260     if( result == paNoError )
1261         AddOpenStream( *stream );
1262 
1263 
1264     PA_LOGAPI(("Pa_OpenStream returned:\n" ));
1265     PA_LOGAPI(("\t*(PaStream** stream): 0x%p\n", *stream ));
1266     PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ));
1267 
1268     return result;
1269 }
1270 
1271 
Pa_OpenDefaultStream(PaStream ** stream,int inputChannelCount,int outputChannelCount,PaSampleFormat sampleFormat,double sampleRate,unsigned long framesPerBuffer,PaStreamCallback * streamCallback,void * userData)1272 PaError Pa_OpenDefaultStream( PaStream** stream,
1273                               int inputChannelCount,
1274                               int outputChannelCount,
1275                               PaSampleFormat sampleFormat,
1276                               double sampleRate,
1277                               unsigned long framesPerBuffer,
1278                               PaStreamCallback *streamCallback,
1279                               void *userData )
1280 {
1281     PaError result;
1282     PaStreamParameters hostApiInputParameters, hostApiOutputParameters;
1283     PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;
1284 
1285     PA_LOGAPI_ENTER_PARAMS( "Pa_OpenDefaultStream" );
1286     PA_LOGAPI(("\tPaStream** stream: 0x%p\n", stream ));
1287     PA_LOGAPI(("\tint inputChannelCount: %d\n", inputChannelCount ));
1288     PA_LOGAPI(("\tint outputChannelCount: %d\n", outputChannelCount ));
1289     PA_LOGAPI(("\tPaSampleFormat sampleFormat: %d\n", sampleFormat ));
1290     PA_LOGAPI(("\tdouble sampleRate: %g\n", sampleRate ));
1291     PA_LOGAPI(("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer ));
1292     PA_LOGAPI(("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback ));
1293     PA_LOGAPI(("\tvoid *userData: 0x%p\n", userData ));
1294 
1295 
1296     if( inputChannelCount > 0 )
1297     {
1298         hostApiInputParameters.device = Pa_GetDefaultInputDevice();
1299 		if( hostApiInputParameters.device == paNoDevice )
1300 			return paDeviceUnavailable;
1301 
1302         hostApiInputParameters.channelCount = inputChannelCount;
1303         hostApiInputParameters.sampleFormat = sampleFormat;
1304         /* defaultHighInputLatency is used below instead of
1305            defaultLowInputLatency because it is more important for the default
1306            stream to work reliably than it is for it to work with the lowest
1307            latency.
1308          */
1309         hostApiInputParameters.suggestedLatency =
1310              Pa_GetDeviceInfo( hostApiInputParameters.device )->defaultHighInputLatency;
1311         hostApiInputParameters.hostApiSpecificStreamInfo = NULL;
1312         hostApiInputParametersPtr = &hostApiInputParameters;
1313     }
1314     else
1315     {
1316         hostApiInputParametersPtr = NULL;
1317     }
1318 
1319     if( outputChannelCount > 0 )
1320     {
1321         hostApiOutputParameters.device = Pa_GetDefaultOutputDevice();
1322 		if( hostApiOutputParameters.device == paNoDevice )
1323 			return paDeviceUnavailable;
1324 
1325         hostApiOutputParameters.channelCount = outputChannelCount;
1326         hostApiOutputParameters.sampleFormat = sampleFormat;
1327         /* defaultHighOutputLatency is used below instead of
1328            defaultLowOutputLatency because it is more important for the default
1329            stream to work reliably than it is for it to work with the lowest
1330            latency.
1331          */
1332         hostApiOutputParameters.suggestedLatency =
1333              Pa_GetDeviceInfo( hostApiOutputParameters.device )->defaultHighOutputLatency;
1334         hostApiOutputParameters.hostApiSpecificStreamInfo = NULL;
1335         hostApiOutputParametersPtr = &hostApiOutputParameters;
1336     }
1337     else
1338     {
1339         hostApiOutputParametersPtr = NULL;
1340     }
1341 
1342 
1343     result = Pa_OpenStream(
1344                  stream, hostApiInputParametersPtr, hostApiOutputParametersPtr,
1345                  sampleRate, framesPerBuffer, paNoFlag, streamCallback, userData );
1346 
1347     PA_LOGAPI(("Pa_OpenDefaultStream returned:\n" ));
1348     PA_LOGAPI(("\t*(PaStream** stream): 0x%p", *stream ));
1349     PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ));
1350 
1351     return result;
1352 }
1353 
1354 
PaUtil_ValidateStreamPointer(PaStream * stream)1355 PaError PaUtil_ValidateStreamPointer( PaStream* stream )
1356 {
1357     if( !PA_IS_INITIALISED_ ) return paNotInitialized;
1358 
1359     if( stream == NULL ) return paBadStreamPtr;
1360 
1361     if( ((PaUtilStreamRepresentation*)stream)->magic != PA_STREAM_MAGIC )
1362         return paBadStreamPtr;
1363 
1364     return paNoError;
1365 }
1366 
1367 
Pa_CloseStream(PaStream * stream)1368 PaError Pa_CloseStream( PaStream* stream )
1369 {
1370     PaUtilStreamInterface *interface;
1371     PaError result = PaUtil_ValidateStreamPointer( stream );
1372 
1373     PA_LOGAPI_ENTER_PARAMS( "Pa_CloseStream" );
1374     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1375 
1376     /* always remove the open stream from our list, even if this function
1377         eventually returns an error. Otherwise CloseOpenStreams() will
1378         get stuck in an infinite loop */
1379     RemoveOpenStream( stream ); /* be sure to call this _before_ closing the stream */
1380 
1381     if( result == paNoError )
1382     {
1383         interface = PA_STREAM_INTERFACE(stream);
1384 
1385         /* abort the stream if it isn't stopped */
1386         result = interface->IsStopped( stream );
1387         if( result == 1 )
1388             result = paNoError;
1389         else if( result == 0 )
1390             result = interface->Abort( stream );
1391 
1392         if( result == paNoError )                 /** @todo REVIEW: shouldn't we close anyway? see: http://www.portaudio.com/trac/ticket/115 */
1393             result = interface->Close( stream );
1394     }
1395 
1396     PA_LOGAPI_EXIT_PAERROR( "Pa_CloseStream", result );
1397 
1398     return result;
1399 }
1400 
1401 
Pa_SetStreamFinishedCallback(PaStream * stream,PaStreamFinishedCallback * streamFinishedCallback)1402 PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback )
1403 {
1404     PaError result = PaUtil_ValidateStreamPointer( stream );
1405 
1406     PA_LOGAPI_ENTER_PARAMS( "Pa_SetStreamFinishedCallback" );
1407     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1408     PA_LOGAPI(("\tPaStreamFinishedCallback* streamFinishedCallback: 0x%p\n", streamFinishedCallback ));
1409 
1410     if( result == paNoError )
1411     {
1412         result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
1413         if( result == 0 )
1414         {
1415             result = paStreamIsNotStopped ;
1416         }
1417         if( result == 1 )
1418         {
1419             PA_STREAM_REP( stream )->streamFinishedCallback = streamFinishedCallback;
1420             result = paNoError;
1421         }
1422     }
1423 
1424     PA_LOGAPI_EXIT_PAERROR( "Pa_SetStreamFinishedCallback", result );
1425 
1426     return result;
1427 
1428 }
1429 
1430 
Pa_StartStream(PaStream * stream)1431 PaError Pa_StartStream( PaStream *stream )
1432 {
1433     PaError result = PaUtil_ValidateStreamPointer( stream );
1434 
1435     PA_LOGAPI_ENTER_PARAMS( "Pa_StartStream" );
1436     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1437 
1438     if( result == paNoError )
1439     {
1440         result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
1441         if( result == 0 )
1442         {
1443             result = paStreamIsNotStopped ;
1444         }
1445         else if( result == 1 )
1446         {
1447             result = PA_STREAM_INTERFACE(stream)->Start( stream );
1448         }
1449     }
1450 
1451     PA_LOGAPI_EXIT_PAERROR( "Pa_StartStream", result );
1452 
1453     return result;
1454 }
1455 
1456 
Pa_StopStream(PaStream * stream)1457 PaError Pa_StopStream( PaStream *stream )
1458 {
1459     PaError result = PaUtil_ValidateStreamPointer( stream );
1460 
1461     PA_LOGAPI_ENTER_PARAMS( "Pa_StopStream" );
1462     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1463 
1464     if( result == paNoError )
1465     {
1466         result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
1467         if( result == 0 )
1468         {
1469             result = PA_STREAM_INTERFACE(stream)->Stop( stream );
1470         }
1471         else if( result == 1 )
1472         {
1473             result = paStreamIsStopped;
1474         }
1475     }
1476 
1477     PA_LOGAPI_EXIT_PAERROR( "Pa_StopStream", result );
1478 
1479     return result;
1480 }
1481 
1482 
Pa_AbortStream(PaStream * stream)1483 PaError Pa_AbortStream( PaStream *stream )
1484 {
1485     PaError result = PaUtil_ValidateStreamPointer( stream );
1486 
1487     PA_LOGAPI_ENTER_PARAMS( "Pa_AbortStream" );
1488     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1489 
1490     if( result == paNoError )
1491     {
1492         result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
1493         if( result == 0 )
1494         {
1495             result = PA_STREAM_INTERFACE(stream)->Abort( stream );
1496         }
1497         else if( result == 1 )
1498         {
1499             result = paStreamIsStopped;
1500         }
1501     }
1502 
1503     PA_LOGAPI_EXIT_PAERROR( "Pa_AbortStream", result );
1504 
1505     return result;
1506 }
1507 
1508 
Pa_IsStreamStopped(PaStream * stream)1509 PaError Pa_IsStreamStopped( PaStream *stream )
1510 {
1511     PaError result = PaUtil_ValidateStreamPointer( stream );
1512 
1513     PA_LOGAPI_ENTER_PARAMS( "Pa_IsStreamStopped" );
1514     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1515 
1516     if( result == paNoError )
1517         result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
1518 
1519     PA_LOGAPI_EXIT_PAERROR( "Pa_IsStreamStopped", result );
1520 
1521     return result;
1522 }
1523 
1524 
Pa_IsStreamActive(PaStream * stream)1525 PaError Pa_IsStreamActive( PaStream *stream )
1526 {
1527     PaError result = PaUtil_ValidateStreamPointer( stream );
1528 
1529     PA_LOGAPI_ENTER_PARAMS( "Pa_IsStreamActive" );
1530     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1531 
1532     if( result == paNoError )
1533         result = PA_STREAM_INTERFACE(stream)->IsActive( stream );
1534 
1535 
1536     PA_LOGAPI_EXIT_PAERROR( "Pa_IsStreamActive", result );
1537 
1538     return result;
1539 }
1540 
1541 
Pa_GetStreamInfo(PaStream * stream)1542 const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream )
1543 {
1544     PaError error = PaUtil_ValidateStreamPointer( stream );
1545     const PaStreamInfo *result;
1546 
1547     PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamInfo" );
1548     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1549 
1550     if( error != paNoError )
1551     {
1552         result = 0;
1553 
1554         PA_LOGAPI(("Pa_GetStreamInfo returned:\n" ));
1555         PA_LOGAPI(("\tconst PaStreamInfo*: 0 [PaError error:%d ( %s )]\n", error, Pa_GetErrorText( error ) ));
1556 
1557     }
1558     else
1559     {
1560         result = &PA_STREAM_REP( stream )->streamInfo;
1561 
1562         PA_LOGAPI(("Pa_GetStreamInfo returned:\n" ));
1563         PA_LOGAPI(("\tconst PaStreamInfo*: 0x%p:\n", result ));
1564         PA_LOGAPI(("\t{" ));
1565 
1566         PA_LOGAPI(("\t\tint structVersion: %d\n", result->structVersion ));
1567         PA_LOGAPI(("\t\tPaTime inputLatency: %f\n", result->inputLatency ));
1568         PA_LOGAPI(("\t\tPaTime outputLatency: %f\n", result->outputLatency ));
1569         PA_LOGAPI(("\t\tdouble sampleRate: %f\n", result->sampleRate ));
1570         PA_LOGAPI(("\t}\n" ));
1571 
1572     }
1573 
1574     return result;
1575 }
1576 
1577 
Pa_GetStreamTime(PaStream * stream)1578 PaTime Pa_GetStreamTime( PaStream *stream )
1579 {
1580     PaError error = PaUtil_ValidateStreamPointer( stream );
1581     PaTime result;
1582 
1583     PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamTime" );
1584     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1585 
1586     if( error != paNoError )
1587     {
1588         result = 0;
1589 
1590         PA_LOGAPI(("Pa_GetStreamTime returned:\n" ));
1591         PA_LOGAPI(("\tPaTime: 0 [PaError error:%d ( %s )]\n", result, error, Pa_GetErrorText( error ) ));
1592 
1593     }
1594     else
1595     {
1596         result = PA_STREAM_INTERFACE(stream)->GetTime( stream );
1597 
1598         PA_LOGAPI(("Pa_GetStreamTime returned:\n" ));
1599         PA_LOGAPI(("\tPaTime: %g\n", result ));
1600 
1601     }
1602 
1603     return result;
1604 }
1605 
1606 
Pa_GetStreamCpuLoad(PaStream * stream)1607 double Pa_GetStreamCpuLoad( PaStream* stream )
1608 {
1609     PaError error = PaUtil_ValidateStreamPointer( stream );
1610     double result;
1611 
1612     PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamCpuLoad" );
1613     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1614 
1615     if( error != paNoError )
1616     {
1617 
1618         result = 0.0;
1619 
1620         PA_LOGAPI(("Pa_GetStreamCpuLoad returned:\n" ));
1621         PA_LOGAPI(("\tdouble: 0.0 [PaError error: %d ( %s )]\n", error, Pa_GetErrorText( error ) ));
1622 
1623     }
1624     else
1625     {
1626         result = PA_STREAM_INTERFACE(stream)->GetCpuLoad( stream );
1627 
1628         PA_LOGAPI(("Pa_GetStreamCpuLoad returned:\n" ));
1629         PA_LOGAPI(("\tdouble: %g\n", result ));
1630 
1631     }
1632 
1633     return result;
1634 }
1635 
1636 
Pa_ReadStream(PaStream * stream,void * buffer,unsigned long frames)1637 PaError Pa_ReadStream( PaStream* stream,
1638                        void *buffer,
1639                        unsigned long frames )
1640 {
1641     PaError result = PaUtil_ValidateStreamPointer( stream );
1642 
1643     PA_LOGAPI_ENTER_PARAMS( "Pa_ReadStream" );
1644     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1645 
1646     if( result == paNoError )
1647     {
1648         if( frames == 0 )
1649         {
1650             /* @todo Should we not allow the implementation to signal any overflow condition? see: http://www.portaudio.com/trac/ticket/116*/
1651             result = paNoError;
1652         }
1653         else if( buffer == 0 )
1654         {
1655             result = paBadBufferPtr;
1656         }
1657         else
1658         {
1659             result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
1660             if( result == 0 )
1661             {
1662                 result = PA_STREAM_INTERFACE(stream)->Read( stream, buffer, frames );
1663             }
1664             else if( result == 1 )
1665             {
1666                 result = paStreamIsStopped;
1667             }
1668         }
1669     }
1670 
1671     PA_LOGAPI_EXIT_PAERROR( "Pa_ReadStream", result );
1672 
1673     return result;
1674 }
1675 
1676 
Pa_WriteStream(PaStream * stream,const void * buffer,unsigned long frames)1677 PaError Pa_WriteStream( PaStream* stream,
1678                         const void *buffer,
1679                         unsigned long frames )
1680 {
1681     PaError result = PaUtil_ValidateStreamPointer( stream );
1682 
1683     PA_LOGAPI_ENTER_PARAMS( "Pa_WriteStream" );
1684     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1685 
1686     if( result == paNoError )
1687     {
1688         if( frames == 0 )
1689         {
1690             /* @todo Should we not allow the implementation to signal any underflow condition? see: http://www.portaudio.com/trac/ticket/116*/
1691             result = paNoError;
1692         }
1693         else if( buffer == 0 )
1694         {
1695             result = paBadBufferPtr;
1696         }
1697         else
1698         {
1699             result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
1700             if( result == 0 )
1701             {
1702                 result = PA_STREAM_INTERFACE(stream)->Write( stream, buffer, frames );
1703             }
1704             else if( result == 1 )
1705             {
1706                 result = paStreamIsStopped;
1707             }
1708         }
1709     }
1710 
1711     PA_LOGAPI_EXIT_PAERROR( "Pa_WriteStream", result );
1712 
1713     return result;
1714 }
1715 
Pa_GetStreamReadAvailable(PaStream * stream)1716 signed long Pa_GetStreamReadAvailable( PaStream* stream )
1717 {
1718     PaError error = PaUtil_ValidateStreamPointer( stream );
1719     signed long result;
1720 
1721     PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamReadAvailable" );
1722     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1723 
1724     if( error != paNoError )
1725     {
1726         result = 0;
1727 
1728         PA_LOGAPI(("Pa_GetStreamReadAvailable returned:\n" ));
1729         PA_LOGAPI(("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n", error, Pa_GetErrorText( error ) ));
1730 
1731     }
1732     else
1733     {
1734         result = PA_STREAM_INTERFACE(stream)->GetReadAvailable( stream );
1735 
1736         PA_LOGAPI(("Pa_GetStreamReadAvailable returned:\n" ));
1737         PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ));
1738 
1739     }
1740 
1741     return result;
1742 }
1743 
1744 
Pa_GetStreamWriteAvailable(PaStream * stream)1745 signed long Pa_GetStreamWriteAvailable( PaStream* stream )
1746 {
1747     PaError error = PaUtil_ValidateStreamPointer( stream );
1748     signed long result;
1749 
1750     PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamWriteAvailable" );
1751     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1752 
1753     if( error != paNoError )
1754     {
1755         result = 0;
1756 
1757         PA_LOGAPI(("Pa_GetStreamWriteAvailable returned:\n" ));
1758         PA_LOGAPI(("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n", error, Pa_GetErrorText( error ) ));
1759 
1760     }
1761     else
1762     {
1763         result = PA_STREAM_INTERFACE(stream)->GetWriteAvailable( stream );
1764 
1765         PA_LOGAPI(("Pa_GetStreamWriteAvailable returned:\n" ));
1766         PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ));
1767 
1768     }
1769 
1770     return result;
1771 }
1772 
1773 
Pa_GetSampleSize(PaSampleFormat format)1774 PaError Pa_GetSampleSize( PaSampleFormat format )
1775 {
1776     int result;
1777 
1778     PA_LOGAPI_ENTER_PARAMS( "Pa_GetSampleSize" );
1779     PA_LOGAPI(("\tPaSampleFormat format: %d\n", format ));
1780 
1781     switch( format & ~paNonInterleaved )
1782     {
1783 
1784     case paUInt8:
1785     case paInt8:
1786         result = 1;
1787         break;
1788 
1789     case paInt16:
1790         result = 2;
1791         break;
1792 
1793     case paInt24:
1794         result = 3;
1795         break;
1796 
1797     case paFloat32:
1798     case paInt32:
1799         result = 4;
1800         break;
1801 
1802     default:
1803         result = paSampleFormatNotSupported;
1804         break;
1805     }
1806 
1807     PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_GetSampleSize", "int: %d", result );
1808 
1809     return (PaError) result;
1810 }
1811 
1812