I'm using Audio Unit Framework to develop a VOIP app on mac os x. In my program, I set up an input AUHAL and use the default stream format (44.1kHz,32bit/channel) to capture the audio from mic. In this case, my program works fine.
Here is the Code:
//The default setting in my program
CheckError(AudioUnitGetProperty(m_audCapUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output, //the value is 0
inputBus, //the value is 1
&m_audCapUnitOutputStreamFormat,
&propertySize),
"Couldn't get OutputSample ASBD from input unit") ;
//the inOutputSampleRate is 44100.0
m_audCapUnitOutputStreamFormat.mSampleRate = inOutputSampleRate ;
CheckError(AudioUnitSetProperty(m_audCapUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
inputBus,
&m_audCapUnitOutputStreamFormat,
propertySize),
"Couldn't set OutputSample ASBD on input unit");
//
Since I'm developing a VOIP app, the default format (44.1kHz, 32bits/Channel) isn't appropriate for my program, so I want to change the sample rate to 8kHz. And I had written this code to change the format in my program:
//......
inOutputFormat.mSampleRate = 8000. ;
inOutputFormat.mFormatID = kAudioFormatLinearPCM ;
inOutputFormat.mChannelsPerFrame = 2 ;
inOutputFormat.mBitsPerChannel = 16 ;
inOutputFormat.mBytesPerFrame = 2 ;
inOutputFormat.mBytesPerPacket = 2 ;
inOutputFormat.mFramesPerPacket = 1 ;
inOutputFormat.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical ;
inOutputFormat.mReserved = 0 ;
CheckError(AudioUnitSetProperty(m_audCapUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
inputBus,
&inOutputFormat,
ui32PropSize),
"Couldn't set AUHAL Unit Output Format") ;
//.......
In this case, the program works fine until my program calls the AudioUnitRender
in the callback function; it fails to call the AudioUnitRender
with an error code -10876
that means
kAudioUnitErr_NoConnection
in the documentation. The error code puzzled me so much, so I googled it but I couldn't find any useful information. Can someone tell me what the error actually means?
This is not the end, I changed the format again by this code:
//.....
inOutputFormat.mSampleRate = 8000. ;
inOutputFormat.mFormatID = kAudioFormatLinearPCM ;
inOutputFormat.mChannelsPerFrame = 2 ;
inOutputFormat.mBitsPerChannel = 32 ;
inOutputFormat.mBytesPerFrame = 4 ;
inOutputFormat.mBytesPerPacket = 4 ;
inOutputFormat.mFramesPerPacket = 1 ;
inOutputFormat.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical ;
inOutputFormat.mReserved = 0 ;
CheckError(AudioUnitSetProperty(m_audCapUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
inputBus,
&inOutputFormat,
ui32PropSize),
"Couldn't set AUHAL Unit Output Format") ;
//........
In this case, the program failed to call the AudioUnitRender
again and returned another error code -10863(kAudioUnitErr_CannotDoInCurrentContext)
. I googled it, but I found
something useful. After reading the information there, I guess the sample rate or format that I set on the AUHAL may not be supported by the hardware.
So I wrote some code to check the available sample rates on the default input device:
//..........
UInt32 propertySize = sizeof(AudioDeviceID) ;
Boolean isWritable = false ;
CheckError(AudioDeviceGetPropertyInfo(inDeviceID, //the inDeviceID is the default input device
0,
true,
kAudioDevicePropertyAvailableNominalSampleRates,
&propertySize,
&isWritable),
"Get the Available Sample Rate Count Failed") ;
m_valueCount = propertySize / sizeof(AudioValueRange) ;
printf("Available %d Sample Rate\n",m_valueCount) ;
CheckError(AudioDeviceGetProperty(inDeviceID,
0,
false,
kAudioDevicePropertyAvailableNominalSampleRates,
&propertySize,
m_valueTabe),
"Get the Available Sample Rate Count Failed") ;
for(UInt32 i = 0 ; i < m_valueCount ; ++i)
{
printf("Available Sample Rate value : %ld\n",(long)m_valueTabe[i].mMinimum) ;
}
//..............
And then I found the available sample rates are 8000, 16000, 32000, 44100, 48000, 88200, and 96000.
The 8000 sample rate is what I set just before, but I get an error code by calling AudioUnitRender
, I just want to say, why ?
I had google so much and also read many documentations, but I can't get the answer, can someone solve this problem what I encounter?
In other words; how do I change the sample rate or format on an input-only AUHAL?
Finally I fixed this problem yesterday by myself.
Here is my solution:
AudioDeviceGetProperty
to get the available format list on my defaut input device, then I found the available format list contain :8khz, 16khz, 32khz, 44.1khz, 48khz, 88.2khz,96khz
(I just list the sample rate field here ,but there are other field in the list).(8khz,32bits/Channel)
and useAudioDeviceSetProperty
to set it on the default device but not the AUHAL , this is the key that my program work fine after setinng the format on the AUHAL (OutputScope , inputBus).AudioUnitSetProperty
to set the format I wanted , the program work fine.Through this problem and solution , I guess if I want to set the format on the input-only AUHAL ,the format must be match or can be shift to the available format which the input device is using. So what I need to do is setting the format on the input device firstly and set the format on the input-only AUHAL next.