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?
The AUHAL is a more generalized version of the default output unit. In addition to the audio converter and channel mapping capabilities, you can specify the device to connect to by setting the kAudioOutputUnitProperty_CurrentDevice property to the ID of an AudioDevice object in the HAL.
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 use AudioDeviceSetProperty
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.
In my experience, using settings other than 44.1kHz and 16 bit audio results in all sorts of weird errors. Some generic suggestions which might set you on the right path:
Your answer was very helpful for me. However, the use of AudioDeviceGetProperty is depreciated. The following listing may be helpful to get things up to date. As an example the sample rate is set to 32 kHz.
// Get the available sample rates of the default input device.
defaultDeviceProperty.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
CheckError (AudioObjectGetPropertyDataSize(defaultDevice,
&defaultDeviceProperty,
0,
NULL,
&propertySize),
"Couldn't get sample rate count");
int m_valueCount = propertySize / sizeof(AudioValueRange) ;
printf("Available %d Sample Rates\n",m_valueCount) ;
AudioValueRange m_valueTabe[m_valueCount];
CheckError (AudioObjectGetPropertyData(defaultDevice,
&defaultDeviceProperty,
0,
NULL,
&propertySize,
m_valueTabe),
"Couldn't get available sample rates");
for(UInt32 i = 0 ; i < m_valueCount ; ++i)
{
printf("Available Sample Rate value : %f\n", m_valueTabe[i].mMinimum) ;
}
// Set the sample rate to one of the available values.
AudioValueRange inputSampleRate;
inputSampleRate.mMinimum = 32000;
inputSampleRate.mMaximum = 32000;
defaultDeviceProperty.mSelector = kAudioDevicePropertyNominalSampleRate;
CheckError (AudioObjectSetPropertyData(defaultDevice,
&defaultDeviceProperty,
0,
NULL,
sizeof(inputSampleRate),
&inputSampleRate),
"Couldn't get available sample rates");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With