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         PA_STREAM_REP(*stream)->hostApiType = hostApi->info.type;
1263     }
1264 
1265 
1266     PA_LOGAPI(("Pa_OpenStream returned:\n" ));
1267     PA_LOGAPI(("\t*(PaStream** stream): 0x%p\n", *stream ));
1268     PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ));
1269 
1270     return result;
1271 }
1272 
1273 
Pa_OpenDefaultStream(PaStream ** stream,int inputChannelCount,int outputChannelCount,PaSampleFormat sampleFormat,double sampleRate,unsigned long framesPerBuffer,PaStreamCallback * streamCallback,void * userData)1274 PaError Pa_OpenDefaultStream( PaStream** stream,
1275                               int inputChannelCount,
1276                               int outputChannelCount,
1277                               PaSampleFormat sampleFormat,
1278                               double sampleRate,
1279                               unsigned long framesPerBuffer,
1280                               PaStreamCallback *streamCallback,
1281                               void *userData )
1282 {
1283     PaError result;
1284     PaStreamParameters hostApiInputParameters, hostApiOutputParameters;
1285     PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;
1286 
1287     PA_LOGAPI_ENTER_PARAMS( "Pa_OpenDefaultStream" );
1288     PA_LOGAPI(("\tPaStream** stream: 0x%p\n", stream ));
1289     PA_LOGAPI(("\tint inputChannelCount: %d\n", inputChannelCount ));
1290     PA_LOGAPI(("\tint outputChannelCount: %d\n", outputChannelCount ));
1291     PA_LOGAPI(("\tPaSampleFormat sampleFormat: %d\n", sampleFormat ));
1292     PA_LOGAPI(("\tdouble sampleRate: %g\n", sampleRate ));
1293     PA_LOGAPI(("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer ));
1294     PA_LOGAPI(("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback ));
1295     PA_LOGAPI(("\tvoid *userData: 0x%p\n", userData ));
1296 
1297 
1298     if( inputChannelCount > 0 )
1299     {
1300         hostApiInputParameters.device = Pa_GetDefaultInputDevice();
1301 		if( hostApiInputParameters.device == paNoDevice )
1302 			return paDeviceUnavailable;
1303 
1304         hostApiInputParameters.channelCount = inputChannelCount;
1305         hostApiInputParameters.sampleFormat = sampleFormat;
1306         /* defaultHighInputLatency is used below instead of
1307            defaultLowInputLatency because it is more important for the default
1308            stream to work reliably than it is for it to work with the lowest
1309            latency.
1310          */
1311         hostApiInputParameters.suggestedLatency =
1312              Pa_GetDeviceInfo( hostApiInputParameters.device )->defaultHighInputLatency;
1313         hostApiInputParameters.hostApiSpecificStreamInfo = NULL;
1314         hostApiInputParametersPtr = &hostApiInputParameters;
1315     }
1316     else
1317     {
1318         hostApiInputParametersPtr = NULL;
1319     }
1320 
1321     if( outputChannelCount > 0 )
1322     {
1323         hostApiOutputParameters.device = Pa_GetDefaultOutputDevice();
1324 		if( hostApiOutputParameters.device == paNoDevice )
1325 			return paDeviceUnavailable;
1326 
1327         hostApiOutputParameters.channelCount = outputChannelCount;
1328         hostApiOutputParameters.sampleFormat = sampleFormat;
1329         /* defaultHighOutputLatency is used below instead of
1330            defaultLowOutputLatency because it is more important for the default
1331            stream to work reliably than it is for it to work with the lowest
1332            latency.
1333          */
1334         hostApiOutputParameters.suggestedLatency =
1335              Pa_GetDeviceInfo( hostApiOutputParameters.device )->defaultHighOutputLatency;
1336         hostApiOutputParameters.hostApiSpecificStreamInfo = NULL;
1337         hostApiOutputParametersPtr = &hostApiOutputParameters;
1338     }
1339     else
1340     {
1341         hostApiOutputParametersPtr = NULL;
1342     }
1343 
1344 
1345     result = Pa_OpenStream(
1346                  stream, hostApiInputParametersPtr, hostApiOutputParametersPtr,
1347                  sampleRate, framesPerBuffer, paNoFlag, streamCallback, userData );
1348 
1349     PA_LOGAPI(("Pa_OpenDefaultStream returned:\n" ));
1350     PA_LOGAPI(("\t*(PaStream** stream): 0x%p", *stream ));
1351     PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ));
1352 
1353     return result;
1354 }
1355 
1356 
PaUtil_ValidateStreamPointer(PaStream * stream)1357 PaError PaUtil_ValidateStreamPointer( PaStream* stream )
1358 {
1359     if( !PA_IS_INITIALISED_ ) return paNotInitialized;
1360 
1361     if( stream == NULL ) return paBadStreamPtr;
1362 
1363     if( ((PaUtilStreamRepresentation*)stream)->magic != PA_STREAM_MAGIC )
1364         return paBadStreamPtr;
1365 
1366     return paNoError;
1367 }
1368 
1369 
Pa_CloseStream(PaStream * stream)1370 PaError Pa_CloseStream( PaStream* stream )
1371 {
1372     PaUtilStreamInterface *interface;
1373     PaError result = PaUtil_ValidateStreamPointer( stream );
1374 
1375     PA_LOGAPI_ENTER_PARAMS( "Pa_CloseStream" );
1376     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1377 
1378     /* always remove the open stream from our list, even if this function
1379         eventually returns an error. Otherwise CloseOpenStreams() will
1380         get stuck in an infinite loop */
1381     RemoveOpenStream( stream ); /* be sure to call this _before_ closing the stream */
1382 
1383     if( result == paNoError )
1384     {
1385         interface = PA_STREAM_INTERFACE(stream);
1386 
1387         /* abort the stream if it isn't stopped */
1388         result = interface->IsStopped( stream );
1389         if( result == 1 )
1390             result = paNoError;
1391         else if( result == 0 )
1392             result = interface->Abort( stream );
1393 
1394         if( result == paNoError )                 /** @todo REVIEW: shouldn't we close anyway? see: http://www.portaudio.com/trac/ticket/115 */
1395             result = interface->Close( stream );
1396     }
1397 
1398     PA_LOGAPI_EXIT_PAERROR( "Pa_CloseStream", result );
1399 
1400     return result;
1401 }
1402 
1403 
Pa_SetStreamFinishedCallback(PaStream * stream,PaStreamFinishedCallback * streamFinishedCallback)1404 PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback )
1405 {
1406     PaError result = PaUtil_ValidateStreamPointer( stream );
1407 
1408     PA_LOGAPI_ENTER_PARAMS( "Pa_SetStreamFinishedCallback" );
1409     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1410     PA_LOGAPI(("\tPaStreamFinishedCallback* streamFinishedCallback: 0x%p\n", streamFinishedCallback ));
1411 
1412     if( result == paNoError )
1413     {
1414         result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
1415         if( result == 0 )
1416         {
1417             result = paStreamIsNotStopped ;
1418         }
1419         if( result == 1 )
1420         {
1421             PA_STREAM_REP( stream )->streamFinishedCallback = streamFinishedCallback;
1422             result = paNoError;
1423         }
1424     }
1425 
1426     PA_LOGAPI_EXIT_PAERROR( "Pa_SetStreamFinishedCallback", result );
1427 
1428     return result;
1429 
1430 }
1431 
1432 
Pa_StartStream(PaStream * stream)1433 PaError Pa_StartStream( PaStream *stream )
1434 {
1435     PaError result = PaUtil_ValidateStreamPointer( stream );
1436 
1437     PA_LOGAPI_ENTER_PARAMS( "Pa_StartStream" );
1438     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1439 
1440     if( result == paNoError )
1441     {
1442         result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
1443         if( result == 0 )
1444         {
1445             result = paStreamIsNotStopped ;
1446         }
1447         else if( result == 1 )
1448         {
1449             result = PA_STREAM_INTERFACE(stream)->Start( stream );
1450         }
1451     }
1452 
1453     PA_LOGAPI_EXIT_PAERROR( "Pa_StartStream", result );
1454 
1455     return result;
1456 }
1457 
1458 
Pa_StopStream(PaStream * stream)1459 PaError Pa_StopStream( PaStream *stream )
1460 {
1461     PaError result = PaUtil_ValidateStreamPointer( stream );
1462 
1463     PA_LOGAPI_ENTER_PARAMS( "Pa_StopStream" );
1464     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1465 
1466     if( result == paNoError )
1467     {
1468         result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
1469         if( result == 0 )
1470         {
1471             result = PA_STREAM_INTERFACE(stream)->Stop( stream );
1472         }
1473         else if( result == 1 )
1474         {
1475             result = paStreamIsStopped;
1476         }
1477     }
1478 
1479     PA_LOGAPI_EXIT_PAERROR( "Pa_StopStream", result );
1480 
1481     return result;
1482 }
1483 
1484 
Pa_AbortStream(PaStream * stream)1485 PaError Pa_AbortStream( PaStream *stream )
1486 {
1487     PaError result = PaUtil_ValidateStreamPointer( stream );
1488 
1489     PA_LOGAPI_ENTER_PARAMS( "Pa_AbortStream" );
1490     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1491 
1492     if( result == paNoError )
1493     {
1494         result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
1495         if( result == 0 )
1496         {
1497             result = PA_STREAM_INTERFACE(stream)->Abort( stream );
1498         }
1499         else if( result == 1 )
1500         {
1501             result = paStreamIsStopped;
1502         }
1503     }
1504 
1505     PA_LOGAPI_EXIT_PAERROR( "Pa_AbortStream", result );
1506 
1507     return result;
1508 }
1509 
1510 
Pa_IsStreamStopped(PaStream * stream)1511 PaError Pa_IsStreamStopped( PaStream *stream )
1512 {
1513     PaError result = PaUtil_ValidateStreamPointer( stream );
1514 
1515     PA_LOGAPI_ENTER_PARAMS( "Pa_IsStreamStopped" );
1516     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1517 
1518     if( result == paNoError )
1519         result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
1520 
1521     PA_LOGAPI_EXIT_PAERROR( "Pa_IsStreamStopped", result );
1522 
1523     return result;
1524 }
1525 
1526 
Pa_IsStreamActive(PaStream * stream)1527 PaError Pa_IsStreamActive( PaStream *stream )
1528 {
1529     PaError result = PaUtil_ValidateStreamPointer( stream );
1530 
1531     PA_LOGAPI_ENTER_PARAMS( "Pa_IsStreamActive" );
1532     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1533 
1534     if( result == paNoError )
1535         result = PA_STREAM_INTERFACE(stream)->IsActive( stream );
1536 
1537 
1538     PA_LOGAPI_EXIT_PAERROR( "Pa_IsStreamActive", result );
1539 
1540     return result;
1541 }
1542 
1543 
Pa_GetStreamInfo(PaStream * stream)1544 const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream )
1545 {
1546     PaError error = PaUtil_ValidateStreamPointer( stream );
1547     const PaStreamInfo *result;
1548 
1549     PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamInfo" );
1550     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1551 
1552     if( error != paNoError )
1553     {
1554         result = 0;
1555 
1556         PA_LOGAPI(("Pa_GetStreamInfo returned:\n" ));
1557         PA_LOGAPI(("\tconst PaStreamInfo*: 0 [PaError error:%d ( %s )]\n", error, Pa_GetErrorText( error ) ));
1558 
1559     }
1560     else
1561     {
1562         result = &PA_STREAM_REP( stream )->streamInfo;
1563 
1564         PA_LOGAPI(("Pa_GetStreamInfo returned:\n" ));
1565         PA_LOGAPI(("\tconst PaStreamInfo*: 0x%p:\n", result ));
1566         PA_LOGAPI(("\t{" ));
1567 
1568         PA_LOGAPI(("\t\tint structVersion: %d\n", result->structVersion ));
1569         PA_LOGAPI(("\t\tPaTime inputLatency: %f\n", result->inputLatency ));
1570         PA_LOGAPI(("\t\tPaTime outputLatency: %f\n", result->outputLatency ));
1571         PA_LOGAPI(("\t\tdouble sampleRate: %f\n", result->sampleRate ));
1572         PA_LOGAPI(("\t}\n" ));
1573 
1574     }
1575 
1576     return result;
1577 }
1578 
1579 
Pa_GetStreamTime(PaStream * stream)1580 PaTime Pa_GetStreamTime( PaStream *stream )
1581 {
1582     PaError error = PaUtil_ValidateStreamPointer( stream );
1583     PaTime result;
1584 
1585     PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamTime" );
1586     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1587 
1588     if( error != paNoError )
1589     {
1590         result = 0;
1591 
1592         PA_LOGAPI(("Pa_GetStreamTime returned:\n" ));
1593         PA_LOGAPI(("\tPaTime: 0 [PaError error:%d ( %s )]\n", result, error, Pa_GetErrorText( error ) ));
1594 
1595     }
1596     else
1597     {
1598         result = PA_STREAM_INTERFACE(stream)->GetTime( stream );
1599 
1600         PA_LOGAPI(("Pa_GetStreamTime returned:\n" ));
1601         PA_LOGAPI(("\tPaTime: %g\n", result ));
1602 
1603     }
1604 
1605     return result;
1606 }
1607 
1608 
Pa_GetStreamCpuLoad(PaStream * stream)1609 double Pa_GetStreamCpuLoad( PaStream* stream )
1610 {
1611     PaError error = PaUtil_ValidateStreamPointer( stream );
1612     double result;
1613 
1614     PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamCpuLoad" );
1615     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1616 
1617     if( error != paNoError )
1618     {
1619 
1620         result = 0.0;
1621 
1622         PA_LOGAPI(("Pa_GetStreamCpuLoad returned:\n" ));
1623         PA_LOGAPI(("\tdouble: 0.0 [PaError error: %d ( %s )]\n", error, Pa_GetErrorText( error ) ));
1624 
1625     }
1626     else
1627     {
1628         result = PA_STREAM_INTERFACE(stream)->GetCpuLoad( stream );
1629 
1630         PA_LOGAPI(("Pa_GetStreamCpuLoad returned:\n" ));
1631         PA_LOGAPI(("\tdouble: %g\n", result ));
1632 
1633     }
1634 
1635     return result;
1636 }
1637 
1638 
Pa_ReadStream(PaStream * stream,void * buffer,unsigned long frames)1639 PaError Pa_ReadStream( PaStream* stream,
1640                        void *buffer,
1641                        unsigned long frames )
1642 {
1643     PaError result = PaUtil_ValidateStreamPointer( stream );
1644 
1645     PA_LOGAPI_ENTER_PARAMS( "Pa_ReadStream" );
1646     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1647 
1648     if( result == paNoError )
1649     {
1650         if( frames == 0 )
1651         {
1652             /* @todo Should we not allow the implementation to signal any overflow condition? see: http://www.portaudio.com/trac/ticket/116*/
1653             result = paNoError;
1654         }
1655         else if( buffer == 0 )
1656         {
1657             result = paBadBufferPtr;
1658         }
1659         else
1660         {
1661             result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
1662             if( result == 0 )
1663             {
1664                 result = PA_STREAM_INTERFACE(stream)->Read( stream, buffer, frames );
1665             }
1666             else if( result == 1 )
1667             {
1668                 result = paStreamIsStopped;
1669             }
1670         }
1671     }
1672 
1673     PA_LOGAPI_EXIT_PAERROR( "Pa_ReadStream", result );
1674 
1675     return result;
1676 }
1677 
1678 
Pa_WriteStream(PaStream * stream,const void * buffer,unsigned long frames)1679 PaError Pa_WriteStream( PaStream* stream,
1680                         const void *buffer,
1681                         unsigned long frames )
1682 {
1683     PaError result = PaUtil_ValidateStreamPointer( stream );
1684 
1685     PA_LOGAPI_ENTER_PARAMS( "Pa_WriteStream" );
1686     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1687 
1688     if( result == paNoError )
1689     {
1690         if( frames == 0 )
1691         {
1692             /* @todo Should we not allow the implementation to signal any underflow condition? see: http://www.portaudio.com/trac/ticket/116*/
1693             result = paNoError;
1694         }
1695         else if( buffer == 0 )
1696         {
1697             result = paBadBufferPtr;
1698         }
1699         else
1700         {
1701             result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
1702             if( result == 0 )
1703             {
1704                 result = PA_STREAM_INTERFACE(stream)->Write( stream, buffer, frames );
1705             }
1706             else if( result == 1 )
1707             {
1708                 result = paStreamIsStopped;
1709             }
1710         }
1711     }
1712 
1713     PA_LOGAPI_EXIT_PAERROR( "Pa_WriteStream", result );
1714 
1715     return result;
1716 }
1717 
Pa_GetStreamReadAvailable(PaStream * stream)1718 signed long Pa_GetStreamReadAvailable( PaStream* stream )
1719 {
1720     PaError error = PaUtil_ValidateStreamPointer( stream );
1721     signed long result;
1722 
1723     PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamReadAvailable" );
1724     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1725 
1726     if( error != paNoError )
1727     {
1728         result = 0;
1729 
1730         PA_LOGAPI(("Pa_GetStreamReadAvailable returned:\n" ));
1731         PA_LOGAPI(("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n", error, Pa_GetErrorText( error ) ));
1732 
1733     }
1734     else
1735     {
1736         result = PA_STREAM_INTERFACE(stream)->GetReadAvailable( stream );
1737 
1738         PA_LOGAPI(("Pa_GetStreamReadAvailable returned:\n" ));
1739         PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ));
1740 
1741     }
1742 
1743     return result;
1744 }
1745 
1746 
Pa_GetStreamWriteAvailable(PaStream * stream)1747 signed long Pa_GetStreamWriteAvailable( PaStream* stream )
1748 {
1749     PaError error = PaUtil_ValidateStreamPointer( stream );
1750     signed long result;
1751 
1752     PA_LOGAPI_ENTER_PARAMS( "Pa_GetStreamWriteAvailable" );
1753     PA_LOGAPI(("\tPaStream* stream: 0x%p\n", stream ));
1754 
1755     if( error != paNoError )
1756     {
1757         result = 0;
1758 
1759         PA_LOGAPI(("Pa_GetStreamWriteAvailable returned:\n" ));
1760         PA_LOGAPI(("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n", error, Pa_GetErrorText( error ) ));
1761 
1762     }
1763     else
1764     {
1765         result = PA_STREAM_INTERFACE(stream)->GetWriteAvailable( stream );
1766 
1767         PA_LOGAPI(("Pa_GetStreamWriteAvailable returned:\n" ));
1768         PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) ));
1769 
1770     }
1771 
1772     return result;
1773 }
1774 
Pa_GetStreamHostApiType(PaStream * stream)1775 PaHostApiTypeId Pa_GetStreamHostApiType( PaStream* stream )
1776 {
1777     PaError error = PaUtil_ValidateStreamPointer( stream );
1778     PaHostApiTypeId result;
1779 
1780 #ifdef PA_LOG_API_CALLS
1781     PaUtil_DebugPrint("Pa_GetStreamHostApiType called:\n" );
1782     PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
1783 #endif
1784 
1785     if( error == paNoError )
1786     {
1787         result = PA_STREAM_REP(stream)->hostApiType;
1788     }
1789     else
1790     {
1791         result = (PaHostApiTypeId) error;
1792     }
1793 
1794 #ifdef PA_LOG_API_CALLS
1795     PaUtil_DebugPrint("Pa_GetStreamHostApiType returned:\n" );
1796     PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
1797 #endif
1798 
1799     return result;
1800 }
1801 
Pa_GetSampleSize(PaSampleFormat format)1802 PaError Pa_GetSampleSize( PaSampleFormat format )
1803 {
1804     int result;
1805 
1806     PA_LOGAPI_ENTER_PARAMS( "Pa_GetSampleSize" );
1807     PA_LOGAPI(("\tPaSampleFormat format: %d\n", format ));
1808 
1809     switch( format & ~paNonInterleaved )
1810     {
1811 
1812     case paUInt8:
1813     case paInt8:
1814         result = 1;
1815         break;
1816 
1817     case paInt16:
1818         result = 2;
1819         break;
1820 
1821     case paInt24:
1822         result = 3;
1823         break;
1824 
1825     case paFloat32:
1826     case paInt32:
1827         result = 4;
1828         break;
1829 
1830     default:
1831         result = paSampleFormatNotSupported;
1832         break;
1833     }
1834 
1835     PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_GetSampleSize", "int: %d", result );
1836 
1837     return (PaError) result;
1838 }
1839 
1840