pa_hostapi_skeleton.c (28260B)
1 /* 2 * $Id$ 3 * Portable Audio I/O Library skeleton implementation 4 * demonstrates how to use the common functions to implement support 5 * for a host API 6 * 7 * Based on the Open Source API proposed by Ross Bencina 8 * Copyright (c) 1999-2002 Ross Bencina, Phil Burk 9 * 10 * Permission is hereby granted, free of charge, to any person obtaining 11 * a copy of this software and associated documentation files 12 * (the "Software"), to deal in the Software without restriction, 13 * including without limitation the rights to use, copy, modify, merge, 14 * publish, distribute, sublicense, and/or sell copies of the Software, 15 * and to permit persons to whom the Software is furnished to do so, 16 * subject to the following conditions: 17 * 18 * The above copyright notice and this permission notice shall be 19 * included in all copies or substantial portions of the Software. 20 * 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 25 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 26 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 */ 29 30 /* 31 * The text above constitutes the entire PortAudio license; however, 32 * the PortAudio community also makes the following non-binding requests: 33 * 34 * Any person wishing to distribute modifications to the Software is 35 * requested to send the modifications to the original developer so that 36 * they can be incorporated into the canonical version. It is also 37 * requested that these non-binding requests be included along with the 38 * license above. 39 */ 40 41 /** @file 42 @ingroup common_src 43 44 @brief Skeleton implementation of support for a host API. 45 46 This file is provided as a starting point for implementing support for 47 a new host API. It provides examples of how the common code can be used. 48 49 @note IMPLEMENT ME comments are used to indicate functionality 50 which much be customised for each implementation. 51 */ 52 53 54 #include <string.h> /* strlen() */ 55 56 #include "pa_util.h" 57 #include "pa_allocation.h" 58 #include "pa_hostapi.h" 59 #include "pa_stream.h" 60 #include "pa_cpuload.h" 61 #include "pa_process.h" 62 63 64 /* prototypes for functions declared in this file */ 65 66 #ifdef __cplusplus 67 extern "C" 68 { 69 #endif /* __cplusplus */ 70 71 PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); 72 73 #ifdef __cplusplus 74 } 75 #endif /* __cplusplus */ 76 77 78 static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); 79 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, 80 const PaStreamParameters *inputParameters, 81 const PaStreamParameters *outputParameters, 82 double sampleRate ); 83 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, 84 PaStream** s, 85 const PaStreamParameters *inputParameters, 86 const PaStreamParameters *outputParameters, 87 double sampleRate, 88 unsigned long framesPerBuffer, 89 PaStreamFlags streamFlags, 90 PaStreamCallback *streamCallback, 91 void *userData ); 92 static PaError CloseStream( PaStream* stream ); 93 static PaError StartStream( PaStream *stream ); 94 static PaError StopStream( PaStream *stream ); 95 static PaError AbortStream( PaStream *stream ); 96 static PaError IsStreamStopped( PaStream *s ); 97 static PaError IsStreamActive( PaStream *stream ); 98 static PaTime GetStreamTime( PaStream *stream ); 99 static double GetStreamCpuLoad( PaStream* stream ); 100 static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); 101 static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames ); 102 static signed long GetStreamReadAvailable( PaStream* stream ); 103 static signed long GetStreamWriteAvailable( PaStream* stream ); 104 105 106 /* IMPLEMENT ME: a macro like the following one should be used for reporting 107 host errors */ 108 #define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \ 109 PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText ) 110 111 /* PaSkeletonHostApiRepresentation - host api datastructure specific to this implementation */ 112 113 typedef struct 114 { 115 PaUtilHostApiRepresentation inheritedHostApiRep; 116 PaUtilStreamInterface callbackStreamInterface; 117 PaUtilStreamInterface blockingStreamInterface; 118 119 PaUtilAllocationGroup *allocations; 120 121 /* implementation specific data goes here */ 122 } 123 PaSkeletonHostApiRepresentation; /* IMPLEMENT ME: rename this */ 124 125 126 PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) 127 { 128 PaError result = paNoError; 129 int i, deviceCount; 130 PaSkeletonHostApiRepresentation *skeletonHostApi; 131 PaDeviceInfo *deviceInfoArray; 132 133 skeletonHostApi = (PaSkeletonHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaSkeletonHostApiRepresentation) ); 134 if( !skeletonHostApi ) 135 { 136 result = paInsufficientMemory; 137 goto error; 138 } 139 140 skeletonHostApi->allocations = PaUtil_CreateAllocationGroup(); 141 if( !skeletonHostApi->allocations ) 142 { 143 result = paInsufficientMemory; 144 goto error; 145 } 146 147 *hostApi = &skeletonHostApi->inheritedHostApiRep; 148 (*hostApi)->info.structVersion = 1; 149 (*hostApi)->info.type = paInDevelopment; /* IMPLEMENT ME: change to correct type id */ 150 (*hostApi)->info.name = "skeleton implementation"; /* IMPLEMENT ME: change to correct name */ 151 152 (*hostApi)->info.defaultInputDevice = paNoDevice; /* IMPLEMENT ME */ 153 (*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */ 154 155 (*hostApi)->info.deviceCount = 0; 156 157 deviceCount = 0; /* IMPLEMENT ME */ 158 159 if( deviceCount > 0 ) 160 { 161 (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( 162 skeletonHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount ); 163 if( !(*hostApi)->deviceInfos ) 164 { 165 result = paInsufficientMemory; 166 goto error; 167 } 168 169 /* allocate all device info structs in a contiguous block */ 170 deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( 171 skeletonHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount ); 172 if( !deviceInfoArray ) 173 { 174 result = paInsufficientMemory; 175 goto error; 176 } 177 178 for( i=0; i < deviceCount; ++i ) 179 { 180 PaDeviceInfo *deviceInfo = &deviceInfoArray[i]; 181 deviceInfo->structVersion = 2; 182 deviceInfo->hostApi = hostApiIndex; 183 deviceInfo->name = 0; /* IMPLEMENT ME: allocate block and copy name eg: 184 deviceName = (char*)PaUtil_GroupAllocateMemory( skeletonHostApi->allocations, strlen(srcName) + 1 ); 185 if( !deviceName ) 186 { 187 result = paInsufficientMemory; 188 goto error; 189 } 190 strcpy( deviceName, srcName ); 191 deviceInfo->name = deviceName; 192 */ 193 194 deviceInfo->maxInputChannels = 0; /* IMPLEMENT ME */ 195 deviceInfo->maxOutputChannels = 0; /* IMPLEMENT ME */ 196 197 deviceInfo->defaultLowInputLatency = 0.; /* IMPLEMENT ME */ 198 deviceInfo->defaultLowOutputLatency = 0.; /* IMPLEMENT ME */ 199 deviceInfo->defaultHighInputLatency = 0.; /* IMPLEMENT ME */ 200 deviceInfo->defaultHighOutputLatency = 0.; /* IMPLEMENT ME */ 201 202 deviceInfo->defaultSampleRate = 0.; /* IMPLEMENT ME */ 203 204 (*hostApi)->deviceInfos[i] = deviceInfo; 205 ++(*hostApi)->info.deviceCount; 206 } 207 } 208 209 (*hostApi)->Terminate = Terminate; 210 (*hostApi)->OpenStream = OpenStream; 211 (*hostApi)->IsFormatSupported = IsFormatSupported; 212 213 PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, CloseStream, StartStream, 214 StopStream, AbortStream, IsStreamStopped, IsStreamActive, 215 GetStreamTime, GetStreamCpuLoad, 216 PaUtil_DummyRead, PaUtil_DummyWrite, 217 PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); 218 219 PaUtil_InitializeStreamInterface( &skeletonHostApi->blockingStreamInterface, CloseStream, StartStream, 220 StopStream, AbortStream, IsStreamStopped, IsStreamActive, 221 GetStreamTime, PaUtil_DummyGetCpuLoad, 222 ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); 223 224 return result; 225 226 error: 227 if( skeletonHostApi ) 228 { 229 if( skeletonHostApi->allocations ) 230 { 231 PaUtil_FreeAllAllocations( skeletonHostApi->allocations ); 232 PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations ); 233 } 234 235 PaUtil_FreeMemory( skeletonHostApi ); 236 } 237 return result; 238 } 239 240 241 static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) 242 { 243 PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi; 244 245 /* 246 IMPLEMENT ME: 247 - clean up any resources not handled by the allocation group 248 */ 249 250 if( skeletonHostApi->allocations ) 251 { 252 PaUtil_FreeAllAllocations( skeletonHostApi->allocations ); 253 PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations ); 254 } 255 256 PaUtil_FreeMemory( skeletonHostApi ); 257 } 258 259 260 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, 261 const PaStreamParameters *inputParameters, 262 const PaStreamParameters *outputParameters, 263 double sampleRate ) 264 { 265 int inputChannelCount, outputChannelCount; 266 PaSampleFormat inputSampleFormat, outputSampleFormat; 267 268 if( inputParameters ) 269 { 270 inputChannelCount = inputParameters->channelCount; 271 inputSampleFormat = inputParameters->sampleFormat; 272 273 /* all standard sample formats are supported by the buffer adapter, 274 this implementation doesn't support any custom sample formats */ 275 if( inputSampleFormat & paCustomFormat ) 276 return paSampleFormatNotSupported; 277 278 /* unless alternate device specification is supported, reject the use of 279 paUseHostApiSpecificDeviceSpecification */ 280 281 if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) 282 return paInvalidDevice; 283 284 /* check that input device can support inputChannelCount */ 285 if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) 286 return paInvalidChannelCount; 287 288 /* validate inputStreamInfo */ 289 if( inputParameters->hostApiSpecificStreamInfo ) 290 return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ 291 } 292 else 293 { 294 inputChannelCount = 0; 295 } 296 297 if( outputParameters ) 298 { 299 outputChannelCount = outputParameters->channelCount; 300 outputSampleFormat = outputParameters->sampleFormat; 301 302 /* all standard sample formats are supported by the buffer adapter, 303 this implementation doesn't support any custom sample formats */ 304 if( outputSampleFormat & paCustomFormat ) 305 return paSampleFormatNotSupported; 306 307 /* unless alternate device specification is supported, reject the use of 308 paUseHostApiSpecificDeviceSpecification */ 309 310 if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) 311 return paInvalidDevice; 312 313 /* check that output device can support outputChannelCount */ 314 if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) 315 return paInvalidChannelCount; 316 317 /* validate outputStreamInfo */ 318 if( outputParameters->hostApiSpecificStreamInfo ) 319 return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ 320 } 321 else 322 { 323 outputChannelCount = 0; 324 } 325 326 /* 327 IMPLEMENT ME: 328 329 - if a full duplex stream is requested, check that the combination 330 of input and output parameters is supported if necessary 331 332 - check that the device supports sampleRate 333 334 Because the buffer adapter handles conversion between all standard 335 sample formats, the following checks are only required if paCustomFormat 336 is implemented, or under some other unusual conditions. 337 338 - check that input device can support inputSampleFormat, or that 339 we have the capability to convert from inputSampleFormat to 340 a native format 341 342 - check that output device can support outputSampleFormat, or that 343 we have the capability to convert from outputSampleFormat to 344 a native format 345 */ 346 347 348 /* suppress unused variable warnings */ 349 (void) sampleRate; 350 351 return paFormatIsSupported; 352 } 353 354 /* PaSkeletonStream - a stream data structure specifically for this implementation */ 355 356 typedef struct PaSkeletonStream 357 { /* IMPLEMENT ME: rename this */ 358 PaUtilStreamRepresentation streamRepresentation; 359 PaUtilCpuLoadMeasurer cpuLoadMeasurer; 360 PaUtilBufferProcessor bufferProcessor; 361 362 /* IMPLEMENT ME: 363 - implementation specific data goes here 364 */ 365 unsigned long framesPerHostCallback; /* just an example */ 366 } 367 PaSkeletonStream; 368 369 /* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ 370 371 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, 372 PaStream** s, 373 const PaStreamParameters *inputParameters, 374 const PaStreamParameters *outputParameters, 375 double sampleRate, 376 unsigned long framesPerBuffer, 377 PaStreamFlags streamFlags, 378 PaStreamCallback *streamCallback, 379 void *userData ) 380 { 381 PaError result = paNoError; 382 PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi; 383 PaSkeletonStream *stream = 0; 384 unsigned long framesPerHostBuffer = framesPerBuffer; /* these may not be equivalent for all implementations */ 385 int inputChannelCount, outputChannelCount; 386 PaSampleFormat inputSampleFormat, outputSampleFormat; 387 PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; 388 389 390 if( inputParameters ) 391 { 392 inputChannelCount = inputParameters->channelCount; 393 inputSampleFormat = inputParameters->sampleFormat; 394 395 /* unless alternate device specification is supported, reject the use of 396 paUseHostApiSpecificDeviceSpecification */ 397 398 if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) 399 return paInvalidDevice; 400 401 /* check that input device can support inputChannelCount */ 402 if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) 403 return paInvalidChannelCount; 404 405 /* validate inputStreamInfo */ 406 if( inputParameters->hostApiSpecificStreamInfo ) 407 return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ 408 409 /* IMPLEMENT ME - establish which host formats are available */ 410 hostInputSampleFormat = 411 PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat ); 412 } 413 else 414 { 415 inputChannelCount = 0; 416 inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */ 417 } 418 419 if( outputParameters ) 420 { 421 outputChannelCount = outputParameters->channelCount; 422 outputSampleFormat = outputParameters->sampleFormat; 423 424 /* unless alternate device specification is supported, reject the use of 425 paUseHostApiSpecificDeviceSpecification */ 426 427 if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) 428 return paInvalidDevice; 429 430 /* check that output device can support inputChannelCount */ 431 if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) 432 return paInvalidChannelCount; 433 434 /* validate outputStreamInfo */ 435 if( outputParameters->hostApiSpecificStreamInfo ) 436 return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ 437 438 /* IMPLEMENT ME - establish which host formats are available */ 439 hostOutputSampleFormat = 440 PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat ); 441 } 442 else 443 { 444 outputChannelCount = 0; 445 outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */ 446 } 447 448 /* 449 IMPLEMENT ME: 450 451 ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? ) 452 453 - check that input device can support inputSampleFormat, or that 454 we have the capability to convert from outputSampleFormat to 455 a native format 456 457 - check that output device can support outputSampleFormat, or that 458 we have the capability to convert from outputSampleFormat to 459 a native format 460 461 - if a full duplex stream is requested, check that the combination 462 of input and output parameters is supported 463 464 - check that the device supports sampleRate 465 466 - alter sampleRate to a close allowable rate if possible / necessary 467 468 - validate suggestedInputLatency and suggestedOutputLatency parameters, 469 use default values where necessary 470 */ 471 472 473 474 475 /* validate platform specific flags */ 476 if( (streamFlags & paPlatformSpecificFlags) != 0 ) 477 return paInvalidFlag; /* unexpected platform specific flag */ 478 479 480 stream = (PaSkeletonStream*)PaUtil_AllocateMemory( sizeof(PaSkeletonStream) ); 481 if( !stream ) 482 { 483 result = paInsufficientMemory; 484 goto error; 485 } 486 487 if( streamCallback ) 488 { 489 PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, 490 &skeletonHostApi->callbackStreamInterface, streamCallback, userData ); 491 } 492 else 493 { 494 PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, 495 &skeletonHostApi->blockingStreamInterface, streamCallback, userData ); 496 } 497 498 PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); 499 500 501 /* we assume a fixed host buffer size in this example, but the buffer processor 502 can also support bounded and unknown host buffer sizes by passing 503 paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of 504 paUtilFixedHostBufferSize below. */ 505 506 result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, 507 inputChannelCount, inputSampleFormat, hostInputSampleFormat, 508 outputChannelCount, outputSampleFormat, hostOutputSampleFormat, 509 sampleRate, streamFlags, framesPerBuffer, 510 framesPerHostBuffer, paUtilFixedHostBufferSize, 511 streamCallback, userData ); 512 if( result != paNoError ) 513 goto error; 514 515 516 /* 517 IMPLEMENT ME: initialise the following fields with estimated or actual 518 values. 519 */ 520 stream->streamRepresentation.streamInfo.inputLatency = 521 (PaTime)PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor) / sampleRate; /* inputLatency is specified in _seconds_ */ 522 stream->streamRepresentation.streamInfo.outputLatency = 523 (PaTime)PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor) / sampleRate; /* outputLatency is specified in _seconds_ */ 524 stream->streamRepresentation.streamInfo.sampleRate = sampleRate; 525 526 527 /* 528 IMPLEMENT ME: 529 - additional stream setup + opening 530 */ 531 532 stream->framesPerHostCallback = framesPerHostBuffer; 533 534 *s = (PaStream*)stream; 535 536 return result; 537 538 error: 539 if( stream ) 540 PaUtil_FreeMemory( stream ); 541 542 return result; 543 } 544 545 /* 546 ExampleHostProcessingLoop() illustrates the kind of processing which may 547 occur in a host implementation. 548 549 */ 550 static void ExampleHostProcessingLoop( void *inputBuffer, void *outputBuffer, void *userData ) 551 { 552 PaSkeletonStream *stream = (PaSkeletonStream*)userData; 553 PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */ 554 int callbackResult; 555 unsigned long framesProcessed; 556 557 PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); 558 559 /* 560 IMPLEMENT ME: 561 - generate timing information 562 - handle buffer slips 563 */ 564 565 /* 566 If you need to byte swap or shift inputBuffer to convert it into a 567 portaudio format, do it here. 568 */ 569 570 571 572 PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */ ); 573 574 /* 575 depending on whether the host buffers are interleaved, non-interleaved 576 or a mixture, you will want to call PaUtil_SetInterleaved*Channels(), 577 PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here. 578 */ 579 580 PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ ); 581 PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 582 0, /* first channel of inputBuffer is channel 0 */ 583 inputBuffer, 584 0 ); /* 0 - use inputChannelCount passed to init buffer processor */ 585 586 PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ ); 587 PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 588 0, /* first channel of outputBuffer is channel 0 */ 589 outputBuffer, 590 0 ); /* 0 - use outputChannelCount passed to init buffer processor */ 591 592 /* you must pass a valid value of callback result to PaUtil_EndBufferProcessing() 593 in general you would pass paContinue for normal operation, and 594 paComplete to drain the buffer processor's internal output buffer. 595 You can check whether the buffer processor's output buffer is empty 596 using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor ) 597 */ 598 callbackResult = paContinue; 599 framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); 600 601 602 /* 603 If you need to byte swap or shift outputBuffer to convert it to 604 host format, do it here. 605 */ 606 607 PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); 608 609 610 if( callbackResult == paContinue ) 611 { 612 /* nothing special to do */ 613 } 614 else if( callbackResult == paAbort ) 615 { 616 /* IMPLEMENT ME - finish playback immediately */ 617 618 /* once finished, call the finished callback */ 619 if( stream->streamRepresentation.streamFinishedCallback != 0 ) 620 stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); 621 } 622 else 623 { 624 /* User callback has asked us to stop with paComplete or other non-zero value */ 625 626 /* IMPLEMENT ME - finish playback once currently queued audio has completed */ 627 628 /* once finished, call the finished callback */ 629 if( stream->streamRepresentation.streamFinishedCallback != 0 ) 630 stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); 631 } 632 } 633 634 635 /* 636 When CloseStream() is called, the multi-api layer ensures that 637 the stream has already been stopped or aborted. 638 */ 639 static PaError CloseStream( PaStream* s ) 640 { 641 PaError result = paNoError; 642 PaSkeletonStream *stream = (PaSkeletonStream*)s; 643 644 /* 645 IMPLEMENT ME: 646 - additional stream closing + cleanup 647 */ 648 649 PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); 650 PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); 651 PaUtil_FreeMemory( stream ); 652 653 return result; 654 } 655 656 657 static PaError StartStream( PaStream *s ) 658 { 659 PaError result = paNoError; 660 PaSkeletonStream *stream = (PaSkeletonStream*)s; 661 662 PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); 663 664 /* IMPLEMENT ME, see portaudio.h for required behavior */ 665 666 /* suppress unused function warning. the code in ExampleHostProcessingLoop or 667 something similar should be implemented to feed samples to and from the 668 host after StartStream() is called. 669 */ 670 (void) ExampleHostProcessingLoop; 671 672 return result; 673 } 674 675 676 static PaError StopStream( PaStream *s ) 677 { 678 PaError result = paNoError; 679 PaSkeletonStream *stream = (PaSkeletonStream*)s; 680 681 /* suppress unused variable warnings */ 682 (void) stream; 683 684 /* IMPLEMENT ME, see portaudio.h for required behavior */ 685 686 return result; 687 } 688 689 690 static PaError AbortStream( PaStream *s ) 691 { 692 PaError result = paNoError; 693 PaSkeletonStream *stream = (PaSkeletonStream*)s; 694 695 /* suppress unused variable warnings */ 696 (void) stream; 697 698 /* IMPLEMENT ME, see portaudio.h for required behavior */ 699 700 return result; 701 } 702 703 704 static PaError IsStreamStopped( PaStream *s ) 705 { 706 PaSkeletonStream *stream = (PaSkeletonStream*)s; 707 708 /* suppress unused variable warnings */ 709 (void) stream; 710 711 /* IMPLEMENT ME, see portaudio.h for required behavior */ 712 713 return 0; 714 } 715 716 717 static PaError IsStreamActive( PaStream *s ) 718 { 719 PaSkeletonStream *stream = (PaSkeletonStream*)s; 720 721 /* suppress unused variable warnings */ 722 (void) stream; 723 724 /* IMPLEMENT ME, see portaudio.h for required behavior */ 725 726 return 0; 727 } 728 729 730 static PaTime GetStreamTime( PaStream *s ) 731 { 732 PaSkeletonStream *stream = (PaSkeletonStream*)s; 733 734 /* suppress unused variable warnings */ 735 (void) stream; 736 737 /* IMPLEMENT ME, see portaudio.h for required behavior*/ 738 739 return 0; 740 } 741 742 743 static double GetStreamCpuLoad( PaStream* s ) 744 { 745 PaSkeletonStream *stream = (PaSkeletonStream*)s; 746 747 return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); 748 } 749 750 751 /* 752 As separate stream interfaces are used for blocking and callback 753 streams, the following functions can be guaranteed to only be called 754 for blocking streams. 755 */ 756 757 static PaError ReadStream( PaStream* s, 758 void *buffer, 759 unsigned long frames ) 760 { 761 PaSkeletonStream *stream = (PaSkeletonStream*)s; 762 763 /* suppress unused variable warnings */ 764 (void) buffer; 765 (void) frames; 766 (void) stream; 767 768 /* IMPLEMENT ME, see portaudio.h for required behavior*/ 769 770 return paNoError; 771 } 772 773 774 static PaError WriteStream( PaStream* s, 775 const void *buffer, 776 unsigned long frames ) 777 { 778 PaSkeletonStream *stream = (PaSkeletonStream*)s; 779 780 /* suppress unused variable warnings */ 781 (void) buffer; 782 (void) frames; 783 (void) stream; 784 785 /* IMPLEMENT ME, see portaudio.h for required behavior*/ 786 787 return paNoError; 788 } 789 790 791 static signed long GetStreamReadAvailable( PaStream* s ) 792 { 793 PaSkeletonStream *stream = (PaSkeletonStream*)s; 794 795 /* suppress unused variable warnings */ 796 (void) stream; 797 798 /* IMPLEMENT ME, see portaudio.h for required behavior*/ 799 800 return 0; 801 } 802 803 804 static signed long GetStreamWriteAvailable( PaStream* s ) 805 { 806 PaSkeletonStream *stream = (PaSkeletonStream*)s; 807 808 /* suppress unused variable warnings */ 809 (void) stream; 810 811 /* IMPLEMENT ME, see portaudio.h for required behavior*/ 812 813 return 0; 814 } 815 816 817 818