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