How to properly perform a sample rate conversion in AVAudioEngine's nodes?

So basically I have a handful of audio effects the are particularly designed under common 44.1kHz sample rate. (Algorithms are written in c++.) I also implemented my own block-wise sample rate conversion algorithm (basically linear or higher order Lagrange interpolation), specifically for the non-44.1kHz cases caused by the insertion of the headphone.
Now my problem is:
  1. Is it even possible for an AVAudioEngine to have different sample rates for inputNode and outputNode ? (And also mainMixerNode)

  2. My first try on performing my own resampling in callback function gives error with OSStatus error code -10863 and -50, I know it is extremely hard to tell what the problem is just by this information, but what could be the cause? (Definitely caused by the sample rate mismatch, but is it because I'm pulling too many samples?)

  3. If it is super tricky to perform resampling ourselves, what is the native way to meet the need (process samples in 44.1kHz) ? should I also care about the sample rate conversion for the output side ? (Or say, would the speaker sample rate also change to meet the new microphone sample rate, caused by the headphone insertion / hardware change) ?

I apologize if I didn't make my problems clear, but I really spent a lot of time and found no working solution. Thank you very much!
Answered by DTS Engineer in 639235022
  1. Yes, input and output can have different rates, except when the configuration requires them to be linked. (For example, if you use voice processing on the input, the input and output rates will be forced to match.)

  2. Error -50 is an invalid parameter error, and error -10863 may indicate you're doing something at an inappropriate time. You can try looking at your console log for additional information that might give clues about what went wrong.

  3. Mixer nodes are documented as handling rate conversions automatically (see https://developer.apple.com/documentation/avfoundation/avaudiomixernode ). You will need to provide custom conversions if your audio has mismatched formats (such as int vs. float samples, or interleaved vs. non-interleaved frames). AVAudioPlayer node is also capable of converting formats from the buffers or file you play to the format of its output bus.

There's a lot of flexibility here, so I can't comment more specifically on the problems you're having without more details.
Accepted Answer
  1. Yes, input and output can have different rates, except when the configuration requires them to be linked. (For example, if you use voice processing on the input, the input and output rates will be forced to match.)

  2. Error -50 is an invalid parameter error, and error -10863 may indicate you're doing something at an inappropriate time. You can try looking at your console log for additional information that might give clues about what went wrong.

  3. Mixer nodes are documented as handling rate conversions automatically (see https://developer.apple.com/documentation/avfoundation/avaudiomixernode ). You will need to provide custom conversions if your audio has mismatched formats (such as int vs. float samples, or interleaved vs. non-interleaved frames). AVAudioPlayer node is also capable of converting formats from the buffers or file you play to the format of its output bus.

There's a lot of flexibility here, so I can't comment more specifically on the problems you're having without more details.
Thank you so much for the reply!
Now the problem becomes: How can I perform callback (micMixerNode.AUAudioUnit.renderBlock) from a mixerNode instead of inputNode?
For the inputNode, my current workaround is
(renderBlockData.renderBlock is actually engine.inputNode.AUAudioUnit.renderBlock)
Code Block
OSStatus status = renderBlockData.renderBlock (
&renderBlockData.flags,
&renderBlockData.timestamp,
512,
1,
renderBlockData.bufferList,
nullptr);

I noticed that if the fourth argument (bus number) is 1 of mixerNode, it will report error -10877 as invalid element.
My guess is that, as I've seen somewhere, 1/0 stands for I/O, so it's correct to put 1 for inputNode, but for mixerNode maybe we need to pull in the opposite direction?
Also, this result in a complete silence, I guess it's because the sixth argument which is a AURenderPullInputBlock is null?
Any ideas? Thank you so much!
Hello, I also ran into error -10863 when trying to load my AU plugin to AU Lab (and the same plugin loads fine on GarageBand). Console log doesn't have much:
Code Block log
AudioUnitGraph.cpp:3333:Open: Open failed with error -10863
AudioUnitGraph.cpp:3008:RemoveNode: RemoveNode failed with error -50

I would also appreciate any ideas on what the error number means and what could be the cause.

EDIT: apparently the error is this one: kAUGraphErr_CannotDoInCurrentContext
How to properly perform a sample rate conversion in AVAudioEngine's nodes?
 
 
Q