Changing setPreferredIOBufferDuration at Runtime r

2019-06-11 00:29发布

问题:

I am writing an Audio Unit (remote IO) based app that displays waveforms at a given buffer size. The app initially starts off with a preferred buffer size of 0.0001 which results in very small buffer frame sizes (i think its 14 frames). Than at runtime I have a UI element that allows switching buffer frame sizes via AVAudioSession's method setPreferredIOBufferDuration:Error:.

Here is the code where the first two cases change from a smaller to a larger sized buffer. 3-5 are not specified yet. But the app crashes at AudioUnitRender with -50 error code.

- (void)setBufferSizeFromMode:(int)mode {

   NSTimeInterval bufferDuration;

   switch (mode) {
      case 1:
         bufferDuration = 0.0001;
         break;
      case 2:
         bufferDuration = 0.001;
         break;
      case 3:
         bufferDuration = 0.0; // reserved
         break;
      case 4:
         bufferDuration = 0.0; // reserved
         break;
      case 5:
         bufferDuration = 0.0; // reserved
         break;
      default:
         break;
   }

   AVAudioSession *session = [AVAudioSession sharedInstance];
   NSError * audioSessionError = nil;

   [session setPreferredIOBufferDuration:bufferDuration error:&audioSessionError];
   if (audioSessionError) {
      NSLog(@"Error %ld, %@",
            (long)audioSessionError.code, audioSessionError.localizedDescription);
   }

}

Based on reading the CoreAudio and AVFoundation documentation, I was led to believe that you can change audio hardware configuration at runtime. There may be some gaps in audio or distortion but I am fine with that for now. Is there an obvious reason for this crash? Or must I reinitialize everything (my audio session, my audio unit, my audio buffers, etc..) for each change of the buffer duration?

Edit: I have tried calling AudioOutputUnitStop(self.myRemoteIO); before changing the session buffer duration and than starting again after it is set. I've also tried setting the session to inactive and than reactivating it but both result with the -50 OSStatus from AudioUnitRender() in my AU input callback.

回答1:

A -50 error usually means the audio unit code is trying to set or use an invalid parameter value.

Some iOS devices don't support actual buffer durations below 5.3 mS (or 0.0058 seconds on older devices). And iOS devices appear free to switch to an actual buffer duration 4X longer than that, or even alternate slightly different values, at times not under the apps control.

The inNumberFrames is given to the audio unit callback as a parameter, your app can't arbitrarily specify that value.

If you want to process given buffer sizes, pull them out of an intermediating lock-free circular FIFO, which the audio unit callback can feed into.

Also: Try waiting a second or so after calling audio stop before changing parameters or restarting. There appears to be a delay between when you call stop, and when the hardware actually stops.