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