📄 pa_mac_core.c
字号:
srConverter ) );
/* Set quality */
ERR_WRAP( AudioConverterSetProperty(
*srConverter,
kAudioConverterSampleRateConverterQuality,
sizeof( value ),
&value ) );
}
}
/* -- set IOProc (callback) -- */
callbackKey = outStreamParams ? kAudioUnitProperty_SetRenderCallback
: kAudioOutputUnitProperty_SetInputCallback ;
rcbs.inputProc = AudioIOProc;
rcbs.inputProcRefCon = refCon;
ERR_WRAP( AudioUnitSetProperty(
*audioUnit,
callbackKey,
kAudioUnitScope_Output,
outStreamParams ? OUTPUT_ELEMENT : INPUT_ELEMENT,
&rcbs,
sizeof(rcbs)) );
if( inStreamParams && outStreamParams && *srConverter )
ERR_WRAP( AudioUnitSetProperty(
*audioUnit,
kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Output,
INPUT_ELEMENT,
&rcbs,
sizeof(rcbs)) );
/*IMPLEMENTME: may need to worry about channel mapping.*/
/* initialize the audio unit */
ERR_WRAP( AudioUnitInitialize(*audioUnit) );
if( inStreamParams && outStreamParams )
VDBUG( ("Opened device %ld for input and output.\n", *audioDevice ) );
else if( inStreamParams )
VDBUG( ("Opened device %ld for input.\n", *audioDevice ) );
else if( outStreamParams )
VDBUG( ("Opened device %ld for output.\n", *audioDevice ) );
return paNoError;
#undef ERR_WRAP
error:
CloseComponent( *audioUnit );
*audioUnit = NULL;
if( result )
return PaMacCore_SetError( result, line, 1 );
return paResult;
}
/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
PaStream** s,
const PaStreamParameters *inputParameters,
const PaStreamParameters *outputParameters,
double sampleRate,
unsigned long framesPerBuffer,
PaStreamFlags streamFlags,
PaStreamCallback *streamCallback,
void *userData )
{
PaError result = paNoError;
PaMacAUHAL *auhalHostApi = (PaMacAUHAL*)hostApi;
PaMacCoreStream *stream = 0;
int inputChannelCount, outputChannelCount;
PaSampleFormat inputSampleFormat, outputSampleFormat;
PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
VVDBUG(("OpenStream(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld SR=%g, FPB=%ld\n",
inputParameters ? inputParameters->channelCount : -1,
inputParameters ? inputParameters->sampleFormat : -1,
outputParameters ? outputParameters->channelCount : -1,
outputParameters ? outputParameters->sampleFormat : -1,
(float) sampleRate,
framesPerBuffer ));
VDBUG( ("Opening Stream.\n") );
/*These first few bits of code are from paSkeleton with few modifications.*/
if( inputParameters )
{
inputChannelCount = inputParameters->channelCount;
inputSampleFormat = inputParameters->sampleFormat;
/* unless alternate device specification is supported, reject the use of
paUseHostApiSpecificDeviceSpecification */
if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
return paInvalidDevice;
/* check that input device can support inputChannelCount */
if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
return paInvalidChannelCount;
/* Host supports interleaved float32 */
hostInputSampleFormat = paFloat32;
}
else
{
inputChannelCount = 0;
inputSampleFormat = hostInputSampleFormat = paFloat32; /* Surpress 'uninitialised var' warnings. */
}
if( outputParameters )
{
outputChannelCount = outputParameters->channelCount;
outputSampleFormat = outputParameters->sampleFormat;
/* unless alternate device specification is supported, reject the use of
paUseHostApiSpecificDeviceSpecification */
if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
return paInvalidDevice;
/* check that output device can support inputChannelCount */
if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
return paInvalidChannelCount;
/* Host supports interleaved float32 */
hostOutputSampleFormat = paFloat32;
}
else
{
outputChannelCount = 0;
outputSampleFormat = hostOutputSampleFormat = paFloat32; /* Surpress 'uninitialized var' warnings. */
}
/* validate platform specific flags */
if( (streamFlags & paPlatformSpecificFlags) != 0 )
return paInvalidFlag; /* unexpected platform specific flag */
stream = (PaMacCoreStream*)PaUtil_AllocateMemory( sizeof(PaMacCoreStream) );
if( !stream )
{
result = paInsufficientMemory;
goto error;
}
/* If we fail after this point, we my be left in a bad state, with
some data structures setup and others not. So, first thing we
do is initialize everything so that if we fail, we know what hasn't
been touched.
*/
stream->inputAudioBufferList.mBuffers[0].mData = NULL;
stream->inputRingBuffer.buffer = NULL;
bzero( &stream->blio, sizeof( PaMacBlio ) );
/*
stream->blio.inputRingBuffer.buffer = NULL;
stream->blio.outputRingBuffer.buffer = NULL;
stream->blio.inputSampleFormat = inputParameters?inputParameters->sampleFormat:0;
stream->blio.inputSampleSize = computeSampleSizeFromFormat(stream->blio.inputSampleFormat);
stream->blio.outputSampleFormat=outputParameters?outputParameters->sampleFormat:0;
stream->blio.outputSampleSize = computeSampleSizeFromFormat(stream->blio.outputSampleFormat);
*/
stream->inputSRConverter = NULL;
stream->inputUnit = NULL;
stream->outputUnit = NULL;
stream->inputFramesPerBuffer = 0;
stream->outputFramesPerBuffer = 0;
stream->bufferProcessorIsInitialized = FALSE;
/* assert( streamCallback ) ; */ /* only callback mode is implemented */
if( streamCallback )
{
PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
&auhalHostApi->callbackStreamInterface,
streamCallback, userData );
}
else
{
PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
&auhalHostApi->blockingStreamInterface,
BlioCallback, &stream->blio );
}
PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
/* -- handle paFramesPerBufferUnspecified -- */
if( framesPerBuffer == paFramesPerBufferUnspecified ) {
long requested = 64;
if( inputParameters )
requested = MAX( requested, inputParameters->suggestedLatency * sampleRate / 2 );
if( outputParameters )
requested = MAX( requested, outputParameters->suggestedLatency *sampleRate / 2 );
VDBUG( ("Block Size unspecified. Based on Latency, the user wants a Block Size near: %ld.\n",
requested ) );
if( requested <= 64 ) {
/*requested a realtively low latency. make sure this is in range of devices */
/*try to get the device's min natural buffer size and use that (but no smaller than 64).*/
AudioValueRange audioRange;
size_t size = sizeof( audioRange );
if( inputParameters ) {
WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[inputParameters->device],
0,
false,
kAudioDevicePropertyBufferFrameSizeRange,
&size, &audioRange ) );
if( result )
requested = MAX( requested, audioRange.mMinimum );
}
if( outputParameters ) {
WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[outputParameters->device],
0,
false,
kAudioDevicePropertyBufferFrameSizeRange,
&size, &audioRange ) );
if( result )
requested = MAX( requested, audioRange.mMinimum );
}
} else {
/* requested a realtively high latency. make sure this is in range of devices */
/*try to get the device's max natural buffer size and use that (but no larger than 1024).*/
AudioValueRange audioRange;
size_t size = sizeof( audioRange );
requested = MIN( requested, 1024 );
if( inputParameters ) {
WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[inputParameters->device],
0,
false,
kAudioDevicePropertyBufferFrameSizeRange,
&size, &audioRange ) );
if( result )
requested = MIN( requested, audioRange.mMaximum );
}
if( outputParameters ) {
WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[outputParameters->device],
0,
false,
kAudioDevicePropertyBufferFrameSizeRange,
&size, &audioRange ) );
if( result )
requested = MIN( requested, audioRange.mMaximum );
}
}
/* -- double check ranges -- */
if( requested > 1024 ) requested = 1024;
if( requested < 64 ) requested = 64;
VDBUG(("After querying hardware, setting block size to %ld.\n", requested));
framesPerBuffer = requested;
}
/* -- Now we actually open and setup streams. -- */
if( inputParameters && outputParameters && outputParameters->device == inputParameters->device )
{ /* full duplex. One device. */
result = OpenAndSetupOneAudioUnit( inputParameters,
outputParameters,
framesPerBuffer,
&(stream->inputFramesPerBuffer),
&(stream->outputFramesPerBuffer),
auhalHostApi,
&(stream->inputUnit),
&(stream->inputSRConverter),
&(stream->inputDevice),
sampleRate,
stream );
stream->outputUnit = stream->inputUnit;
stream->outputDevice = stream->inputDevice;
if( result != paNoError )
goto error;
}
else
{ /* full duplex, different devices OR simplex */
result = OpenAndSetupOneAudioUnit( NULL,
outputParameters,
framesPerBuffer,
NULL,
&(stream->outputFramesPerBuffer),
auhalHostApi,
&(stream->outputUnit),
NULL,
&(stream->outputDevice),
sampleRate,
stream );
if( result != paNoError )
goto error;
result = OpenAndSetupOneAudioUnit( inputParameters,
NULL,
framesPerBuffer,
&(stream->inputFramesPerBuffer),
NULL,
auhalHostApi,
&(stream->inputUnit),
&(stream->inputSRConverter),
&(stream->inputDevice),
sampleRate,
stream );
if( result != paNoError )
goto error;
}
if( stream->inputUnit ) {
const size_t szfl = sizeof(float);
/* setup the AudioBufferList used for input */
bzero( &stream->inputAudioBufferList, sizeof( AudioBufferList ) );
stream->inputAudioBufferList.mNumberBuffers = 1;
stream->inputAudioBufferList.mBuffers[0].mNumberChannels
= inputChannelCount;
stream->inputAudioBufferList.mBuffers[0].mDataByteSize
= stream->inputFramesPerBuffer*inputChannelCount*szfl;
stream->inputAudioBufferList.mBuffers[0].mData
= (float *) calloc(
stream->inputFramesPerBuffer*inputChannelCount,
szfl );
if( !stream->inputAudioBufferList.mBuffers[0].mData )
{
result = paInsufficientMemory;
goto error;
}
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -