📄 pa_mac_core.c
字号:
unsigned long macOutputStreamFlags = paMacCorePlayNice;
VVDBUG(("OpenAndSetupOneAudioUnit(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld, requestedFramesPerBuffer=%ld\n",
inStreamParams ? inStreamParams->channelCount : -1,
inStreamParams ? inStreamParams->sampleFormat : -1,
outStreamParams ? outStreamParams->channelCount : -1,
outStreamParams ? outStreamParams->sampleFormat : -1,
requestedFramesPerBuffer ));
/* -- handle the degenerate case -- */
if( !inStreamParams && !outStreamParams ) {
*audioUnit = NULL;
*audioDevice = kAudioDeviceUnknown;
return paNoError;
}
/* -- get the user's api specific info, if they set any -- */
if( inStreamParams && inStreamParams->hostApiSpecificStreamInfo )
macInputStreamFlags=
((paMacCoreStreamInfo*)inStreamParams->hostApiSpecificStreamInfo)
->flags;
if( outStreamParams && outStreamParams->hostApiSpecificStreamInfo )
macOutputStreamFlags=
((paMacCoreStreamInfo*)outStreamParams->hostApiSpecificStreamInfo)
->flags;
/* Override user's flags here, if desired for testing. */
/*
* The HAL AU is a Mac OS style "component".
* the first few steps deal with that.
* Later steps work on a combination of Mac OS
* components and the slightly lower level
* HAL.
*/
/* -- describe the output type AudioUnit -- */
/* Note: for the default AudioUnit, we could use the
* componentSubType value kAudioUnitSubType_DefaultOutput;
* but I don't think that's relevant here.
*/
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_HALOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
/* -- find the component -- */
comp = FindNextComponent( NULL, &desc );
if( !comp )
{
DBUG( ( "AUHAL component not found." ) );
*audioUnit = NULL;
*audioDevice = kAudioDeviceUnknown;
return paUnanticipatedHostError;
}
/* -- open it -- */
result = OpenAComponent( comp, audioUnit );
if( result )
{
DBUG( ( "Failed to open AUHAL component." ) );
*audioUnit = NULL;
*audioDevice = kAudioDeviceUnknown;
return ERR( result );
}
/* -- prepare a little error handling logic / hackery -- */
#define ERR_WRAP(mac_err) do { result = mac_err ; line = __LINE__ ; if ( result != noErr ) goto error ; } while(0)
/* -- if there is input, we have to explicitly enable input -- */
if( inStreamParams )
{
UInt32 enableIO;
enableIO = 1;
ERR_WRAP( AudioUnitSetProperty( *audioUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
INPUT_ELEMENT,
&enableIO,
sizeof(enableIO) ) );
}
/* -- if there is no output, we must explicitly disable output -- */
if( !outStreamParams )
{
UInt32 enableIO;
enableIO = 0;
ERR_WRAP( AudioUnitSetProperty( *audioUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
OUTPUT_ELEMENT,
&enableIO,
sizeof(enableIO) ) );
}
/* -- set the devices -- */
/* make sure input and output are the same device if we are doing input and
output. */
if( inStreamParams && outStreamParams )
assert( outStreamParams->device == inStreamParams->device );
if( inStreamParams )
{
*audioDevice = auhalHostApi->devIds[inStreamParams->device] ;
ERR_WRAP( AudioUnitSetProperty( *audioUnit,
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global,
INPUT_ELEMENT,
audioDevice,
sizeof(AudioDeviceID) ) );
}
if( outStreamParams )
{
*audioDevice = auhalHostApi->devIds[outStreamParams->device] ;
ERR_WRAP( AudioUnitSetProperty( *audioUnit,
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global,
OUTPUT_ELEMENT,
audioDevice,
sizeof(AudioDeviceID) ) );
}
/* -- set format -- */
bzero( &desiredFormat, sizeof(desiredFormat) );
desiredFormat.mFormatID = kAudioFormatLinearPCM ;
desiredFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
desiredFormat.mFramesPerPacket = 1;
desiredFormat.mBitsPerChannel = sizeof( float ) * 8;
result = 0;
/* set device format first, but only touch the device if the user asked */
if( inStreamParams ) {
/*The callback never calls back if we don't set the FPB */
/*This seems wierd, because I would think setting anything on the device
would be disruptive.*/
paResult = setBestFramesPerBuffer( *audioDevice, FALSE,
requestedFramesPerBuffer,
actualInputFramesPerBuffer );
if( paResult ) goto error;
if( macInputStreamFlags & paMacCore_ChangeDeviceParameters ) {
bool requireExact;
requireExact=macInputStreamFlags&paMacCore_FailIfConversionRequired;
paResult = setBestSampleRateForDevice( *audioDevice, FALSE,
requireExact, sampleRate );
if( paResult ) goto error;
}
if( actualInputFramesPerBuffer && actualOutputFramesPerBuffer )
*actualOutputFramesPerBuffer = *actualInputFramesPerBuffer ;
}
if( outStreamParams && !inStreamParams ) {
/*The callback never calls back if we don't set the FPB */
/*This seems wierd, because I would think setting anything on the device
would be disruptive.*/
paResult = setBestFramesPerBuffer( *audioDevice, TRUE,
requestedFramesPerBuffer,
actualOutputFramesPerBuffer );
if( paResult ) goto error;
if( macOutputStreamFlags & paMacCore_ChangeDeviceParameters ) {
bool requireExact;
requireExact=macOutputStreamFlags&paMacCore_FailIfConversionRequired;
paResult = setBestSampleRateForDevice( *audioDevice, TRUE,
requireExact, sampleRate );
if( paResult ) goto error;
}
}
/* -- set the quality of the output converter -- */
if( outStreamParams ) {
UInt32 value = kAudioConverterQuality_Max;
switch( macOutputStreamFlags & 0x0700 ) {
case 0x0100: /*paMacCore_ConversionQualityMin:*/
value=kRenderQuality_Min;
break;
case 0x0200: /*paMacCore_ConversionQualityLow:*/
value=kRenderQuality_Low;
break;
case 0x0300: /*paMacCore_ConversionQualityMedium:*/
value=kRenderQuality_Medium;
break;
case 0x0400: /*paMacCore_ConversionQualityHigh:*/
value=kRenderQuality_High;
break;
}
ERR_WRAP( AudioUnitSetProperty( *audioUnit,
kAudioUnitProperty_RenderQuality,
kAudioUnitScope_Global,
OUTPUT_ELEMENT,
&value,
sizeof(value) ) );
}
/* now set the format on the Audio Units. */
if( outStreamParams )
{
desiredFormat.mSampleRate =sampleRate;
desiredFormat.mBytesPerPacket=sizeof(float)*outStreamParams->channelCount;
desiredFormat.mBytesPerFrame =sizeof(float)*outStreamParams->channelCount;
desiredFormat.mChannelsPerFrame = outStreamParams->channelCount;
ERR_WRAP( AudioUnitSetProperty( *audioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
OUTPUT_ELEMENT,
&desiredFormat,
sizeof(AudioStreamBasicDescription) ) );
}
if( inStreamParams )
{
AudioStreamBasicDescription sourceFormat;
UInt32 size = sizeof( AudioStreamBasicDescription );
/* keep the sample rate of the device, or we confuse AUHAL */
ERR_WRAP( AudioUnitGetProperty( *audioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
INPUT_ELEMENT,
&sourceFormat,
&size ) );
desiredFormat.mSampleRate = sourceFormat.mSampleRate;
desiredFormat.mBytesPerPacket=sizeof(float)*inStreamParams->channelCount;
desiredFormat.mBytesPerFrame =sizeof(float)*inStreamParams->channelCount;
desiredFormat.mChannelsPerFrame = inStreamParams->channelCount;
ERR_WRAP( AudioUnitSetProperty( *audioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
INPUT_ELEMENT,
&desiredFormat,
sizeof(AudioStreamBasicDescription) ) );
}
/* set the maximumFramesPerSlice */
/* not doing this causes real problems
(eg. the callback might not be called). The idea of setting both this
and the frames per buffer on the device is that we'll be most likely
to actually get the frame size we requested in the callback with the
minimum latency. */
if( outStreamParams ) {
UInt32 size = sizeof( *actualOutputFramesPerBuffer );
ERR_WRAP( AudioUnitSetProperty( *audioUnit,
kAudioUnitProperty_MaximumFramesPerSlice,
kAudioUnitScope_Input,
OUTPUT_ELEMENT,
actualOutputFramesPerBuffer,
sizeof(unsigned long) ) );
ERR_WRAP( AudioUnitGetProperty( *audioUnit,
kAudioUnitProperty_MaximumFramesPerSlice,
kAudioUnitScope_Global,
OUTPUT_ELEMENT,
actualOutputFramesPerBuffer,
&size ) );
}
if( inStreamParams ) {
/*UInt32 size = sizeof( *actualInputFramesPerBuffer );*/
ERR_WRAP( AudioUnitSetProperty( *audioUnit,
kAudioUnitProperty_MaximumFramesPerSlice,
kAudioUnitScope_Output,
INPUT_ELEMENT,
actualInputFramesPerBuffer,
sizeof(unsigned long) ) );
/* Don't know why this causes problems
ERR_WRAP( AudioUnitGetProperty( *audioUnit,
kAudioUnitProperty_MaximumFramesPerSlice,
kAudioUnitScope_Global, //Output,
INPUT_ELEMENT,
actualInputFramesPerBuffer,
&size ) );
*/
}
/* -- if we have input, we may need to setup an SR converter -- */
/* even if we got the sample rate we asked for, we need to do
the conversion in case another program changes the underlying SR. */
/* FIXME: I think we need to monitor stream and change the converter if the incoming format changes. */
if( inStreamParams ) {
AudioStreamBasicDescription desiredFormat;
AudioStreamBasicDescription sourceFormat;
UInt32 sourceSize = sizeof( sourceFormat );
bzero( &desiredFormat, sizeof(desiredFormat) );
desiredFormat.mSampleRate = sampleRate;
desiredFormat.mFormatID = kAudioFormatLinearPCM ;
desiredFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
desiredFormat.mFramesPerPacket = 1;
desiredFormat.mBitsPerChannel = sizeof( float ) * 8;
desiredFormat.mBytesPerPacket=sizeof(float)*inStreamParams->channelCount;
desiredFormat.mBytesPerFrame =sizeof(float)*inStreamParams->channelCount;
desiredFormat.mChannelsPerFrame = inStreamParams->channelCount;
/* get the source format */
ERR_WRAP( AudioUnitGetProperty(
*audioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
INPUT_ELEMENT,
&sourceFormat,
&sourceSize ) );
if( desiredFormat.mSampleRate != sourceFormat.mSampleRate )
{
UInt32 value = kAudioConverterQuality_Max;
switch( macInputStreamFlags & 0x0700 ) {
case 0x0100: /*paMacCore_ConversionQualityMin:*/
value=kAudioConverterQuality_Min;
break;
case 0x0200: /*paMacCore_ConversionQualityLow:*/
value=kAudioConverterQuality_Low;
break;
case 0x0300: /*paMacCore_ConversionQualityMedium:*/
value=kAudioConverterQuality_Medium;
break;
case 0x0400: /*paMacCore_ConversionQualityHigh:*/
value=kAudioConverterQuality_High;
break;
}
VDBUG(( "Creating sample rate converter for input"
" to convert from %g to %g\n",
(float)sourceFormat.mSampleRate,
(float)desiredFormat.mSampleRate ) );
/* create our converter */
ERR_WRAP( AudioConverterNew(
&sourceFormat,
&desiredFormat,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -