pa_front.c (56462B)
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 115 int Pa_GetVersion( void ) 116 { 117 return paVersion; 118 } 119 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 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 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 168 static int CountHostApiInitializers( void ) 169 { 170 int result = 0; 171 172 while( paHostApiInitializers[ result ] != 0 ) 173 ++result; 174 return result; 175 } 176 177 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 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 */ 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 310 static void AddOpenStream( PaStream* stream ) 311 { 312 ((PaUtilStreamRepresentation*)stream)->nextOpenStream = firstOpenStream_; 313 firstOpenStream_ = (PaUtilStreamRepresentation*)stream; 314 } 315 316 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 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 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 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 416 const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void ) 417 { 418 return &lastHostErrorInfo_; 419 } 420 421 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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