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