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