pa_mac_core.c
字号:
if( !data ) { result = paInsufficientMemory; goto error; } /* now we can initialize the ring buffer */ /*assert( 0 ==*/ RingBuffer_Init( &stream->inputRingBuffer, ringSize*szfl, data ) /*)*/; /* advance the read point a little, so we are reading from the middle of the buffer */ if( stream->outputUnit ) RingBuffer_AdvanceWriteIndex( &stream->inputRingBuffer, ringSize*szfl / RING_BUFFER_ADVANCE_DENOMINATOR ); } } /* -- initialize Blio Buffer Processors -- */ if( !streamCallback ) { long ringSize; ringSize = computeRingBufferSize( inputParameters, outputParameters, stream->inputFramesPerBuffer, stream->outputFramesPerBuffer, sampleRate ); result = initializeBlioRingBuffers( &stream->blio, inputParameters?inputParameters->sampleFormat:0 , outputParameters?outputParameters->sampleFormat:0 , MAX(stream->inputFramesPerBuffer,stream->outputFramesPerBuffer), ringSize, inputParameters?inputChannelCount:0 , outputParameters?outputChannelCount:0 ) ; if( result != paNoError ) goto error; } /* -- initialize Buffer Processor -- */ { unsigned long maxHostFrames = stream->inputFramesPerBuffer; if( stream->outputFramesPerBuffer > maxHostFrames ) maxHostFrames = stream->outputFramesPerBuffer; result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, inputChannelCount, inputSampleFormat, hostInputSampleFormat, outputChannelCount, outputSampleFormat, hostOutputSampleFormat, sampleRate, streamFlags, framesPerBuffer, /* If sample rate conversion takes place, the buffer size will not be known. */ maxHostFrames, stream->inputSRConverter ? paUtilUnknownHostBufferSize : paUtilBoundedHostBufferSize, streamCallback ? streamCallback : BlioCallback, streamCallback ? userData : &stream->blio ); if( result != paNoError ) goto error; } stream->bufferProcessorIsInitialized = TRUE; /* IMPLEMENT ME: initialise the following fields with estimated or actual values. I think this is okay the way it is br 12/1/05 maybe need to change input latency estimate if IO devs differ */ stream->streamRepresentation.streamInfo.inputLatency = PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)/sampleRate; stream->streamRepresentation.streamInfo.outputLatency = PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)/sampleRate; stream->streamRepresentation.streamInfo.sampleRate = sampleRate; stream->sampleRate = sampleRate; stream->outDeviceSampleRate = 0; if( stream->outputUnit ) { Float64 rate; UInt32 size = sizeof( rate ); result = ERR( AudioDeviceGetProperty( stream->outputDevice, 0, FALSE, kAudioDevicePropertyNominalSampleRate, &size, &rate ) ); if( result ) goto error; stream->outDeviceSampleRate = rate; } stream->inDeviceSampleRate = 0; if( stream->inputUnit ) { Float64 rate; UInt32 size = sizeof( rate ); result = ERR( AudioDeviceGetProperty( stream->inputDevice, 0, TRUE, kAudioDevicePropertyNominalSampleRate, &size, &rate ) ); if( result ) goto error; stream->inDeviceSampleRate = rate; } stream->userInChan = inputChannelCount; stream->userOutChan = outputChannelCount; stream->isTimeSet = FALSE; stream->state = STOPPED; stream->xrunFlags = 0; *s = (PaStream*)stream; return result;error: CloseStream( stream ); return result;}PaTime GetStreamTime( PaStream *s ){ /* FIXME: I am not at all sure this timing info stuff is right. patest_sine_time reports negative latencies, which is wierd.*/ PaMacCoreStream *stream = (PaMacCoreStream*)s; AudioTimeStamp timeStamp; VVDBUG(("GetStreamTime()\n")); if ( !stream->isTimeSet ) return (PaTime)0; if ( stream->outputDevice ) { AudioDeviceGetCurrentTime( stream->outputDevice, &timeStamp); return (PaTime)(timeStamp.mSampleTime - stream->startTime.mSampleTime)/stream->outDeviceSampleRate; } else if ( stream->inputDevice ) { AudioDeviceGetCurrentTime( stream->inputDevice, &timeStamp); return (PaTime)(timeStamp.mSampleTime - stream->startTime.mSampleTime)/stream->inDeviceSampleRate; } else { return (PaTime)0; }}static void setStreamStartTime( PaStream *stream ){ /* FIXME: I am not at all sure this timing info stuff is right. patest_sine_time reports negative latencies, which is wierd.*/ PaMacCoreStream *s = (PaMacCoreStream *) stream; VVDBUG(("setStreamStartTime()\n")); if( s->outputDevice ) AudioDeviceGetCurrentTime( s->outputDevice, &s->startTime); else if( s->inputDevice ) AudioDeviceGetCurrentTime( s->inputDevice, &s->startTime); else bzero( &s->startTime, sizeof( s->startTime ) ); //FIXME: we need a memory barier here s->isTimeSet = TRUE;}static PaTime TimeStampToSecs(PaMacCoreStream *stream, const AudioTimeStamp* timeStamp){ VVDBUG(("TimeStampToSecs()\n")); //printf( "ATS: %lu, %g, %g\n", timeStamp->mFlags, timeStamp->mSampleTime, timeStamp->mRateScalar ); if (timeStamp->mFlags & kAudioTimeStampSampleTimeValid) return (timeStamp->mSampleTime / stream->sampleRate); else return 0;}#define RING_BUFFER_EMPTY (1000)static OSStatus ringBufferIOProc( AudioConverterRef inAudioConverter, UInt32*ioDataSize, void** outData, void*inUserData ){ void *dummyData; long dummySize; RingBuffer *rb = (RingBuffer *) inUserData; VVDBUG(("ringBufferIOProc()\n")); assert( sizeof( UInt32 ) == sizeof( long ) ); if( RingBuffer_GetReadAvailable( rb ) == 0 ) { *outData = NULL; *ioDataSize = 0; return RING_BUFFER_EMPTY; } RingBuffer_GetReadRegions( rb, *ioDataSize, outData, (long *)ioDataSize, &dummyData, &dummySize ); assert( *ioDataSize ); RingBuffer_AdvanceReadIndex( rb, *ioDataSize ); return noErr;}/* * Called by the AudioUnit API to process audio from the sound card. * This is where the magic happens. *//* FEEDBACK: there is a lot of redundant code here because of how all the cases differ. This makes it hard to maintain, so if there are suggestinos for cleaning it up, I'm all ears. */static OSStatus AudioIOProc( void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData ){ unsigned long framesProcessed = 0; PaStreamCallbackTimeInfo timeInfo = {0,0,0}; PaMacCoreStream *stream = (PaMacCoreStream*)inRefCon; const bool isRender = inBusNumber == OUTPUT_ELEMENT; int callbackResult = paContinue ; VVDBUG(("AudioIOProc()\n")); PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); /* -----------------------------------------------------------------*\ This output may be useful for debugging, But printing durring the callback is a bad enough idea that this is not enabled by enableing the usual debugging calls. \* -----------------------------------------------------------------*/ /* static int renderCount = 0; static int inputCount = 0; printf( "------------------- starting reder/input\n" ); if( isRender ) printf("Render callback (%d):\t", ++renderCount); else printf("Input callback (%d):\t", ++inputCount); printf( "Call totals: %d (input), %d (render)\n", inputCount, renderCount ); printf( "--- inBusNumber: %lu\n", inBusNumber ); printf( "--- inNumberFrames: %lu\n", inNumberFrames ); printf( "--- %x ioData\n", (unsigned) ioData ); if( ioData ) { int i=0; printf( "--- ioData.mNumBuffers %lu: \n", ioData->mNumberBuffers ); for( i=0; i<ioData->mNumberBuffers; ++i ) printf( "--- ioData buffer %d size: %lu.\n", i, ioData->mBuffers[i].mDataByteSize ); } ----------------------------------------------------------------- */ if( !stream->isTimeSet ) setStreamStartTime( stream ); if( isRender ) { AudioTimeStamp currentTime; timeInfo.outputBufferDacTime = TimeStampToSecs(stream, inTimeStamp); AudioDeviceGetCurrentTime(stream->outputDevice, ¤tTime); timeInfo.currentTime = TimeStampToSecs(stream, ¤tTime); } if( isRender && stream->inputUnit == stream->outputUnit ) timeInfo.inputBufferAdcTime = TimeStampToSecs(stream, inTimeStamp); if( !isRender ) { AudioTimeStamp currentTime; timeInfo.inputBufferAdcTime = TimeStampToSecs(stream, inTimeStamp); AudioDeviceGetCurrentTime(stream->inputDevice, ¤tTime); timeInfo.currentTime = TimeStampToSecs(stream, ¤tTime); } //printf( "---%g, %g, %g\n", timeInfo.inputBufferAdcTime, timeInfo.currentTime, timeInfo.outputBufferDacTime ); if( isRender && stream->inputUnit == stream->outputUnit && !stream->inputSRConverter ) { /* --------- Full Duplex, One Device, no SR Conversion ------- * * This is the lowest latency case, and also the simplest. * Input data and output data are available at the same time. * we do not use the input SR converter or the input ring buffer. * */ OSErr err = 0; unsigned long frames; /* -- start processing -- */ PaUtil_BeginBufferProcessing( &(stream->bufferProcessor), &timeInfo, stream->xrunFlags ); stream->xrunFlags = 0; /* -- compute frames. do some checks -- */ assert( ioData->mNumberBuffers == 1 ); assert( ioData->mBuffers[0].mNumberChannels == stream->userOutChan ); frames = ioData->mBuffers[0].mDataByteSize; frames /= sizeof( float ) * ioData->mBuffers[0].mNumberChannels; /* -- copy and process input data -- */ err= AudioUnitRender(stream->inputUnit, ioActionFlags, inTimeStamp, INPUT_ELEMENT, inNumberFrames, &stream->inputAudioBufferList ); /* FEEDBACK: I'm not sure what to do when this call fails */ assert( !err ); PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames ); PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), 0, stream->inputAudioBufferList.mBuffers[0].mData, stream->inputAudioBufferList.mBuffers[0].mNumberChannels); /* -- Copy and process output data -- */ PaUtil_SetOutputFrameCount( &(stream->bufferProcessor), frames ); PaUtil_SetInterleavedOutputChannels( &(stream->bufferProcessor), 0, ioData->mBuffers[0].mData, ioData->mBuffers[0].mNumberChannels); /* -- complete processing -- */ fram
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -