Interference occurs between MTAudioProcessingTaps when using MTAudioProcessingTap from iOS17.1 and later.

There is a CustomPlayer class and inside it is using the MTAudioProcessingTap to modify the Audio buffer.

Let's say there are instances A and B of the Custom Player class. When A and B are running, the process of B's MTAudioProcessingTap is stopped and finalize callback is coming up when A finishes the operation and the instance is terminated.

B is still experiencing this with some parts left to proceed. Same code same project is not happening in iOS 17.0 or lower. At the same time when A is terminated, B can complete the task without any impact on B.

What changes to iOS 17.1 are resulting in these results? I'd appreciate it if you could give me an answer on how to avoid these issues.

let audioMix = AVMutableAudioMix()
var audioMixParameters: [AVMutableAudioMixInputParameters] = []
   try composition.tracks(withMediaType: .audio).forEach { track in
      let inputParameter = AVMutableAudioMixInputParameters(track: track)
      inputParameter.trackID = track.trackID
      var callbacks = MTAudioProcessingTapCallbacks(
         version: kMTAudioProcessingTapCallbacksVersion_0,
         clientInfo: UnsafeMutableRawPointer(
             Unmanaged.passRetained(clientInfo).toOpaque()
         ),
         init: { tap, clientInfo, tapStorageOut in
             tapStorageOut.pointee = clientInfo
         },
         finalize: { tap in
 
Unmanaged<ClientInfo>.fromOpaque(MTAudioProcessingTapGetStorage(tap)).release()  
                },
         prepare: nil,
         unprepare: nil,
         process: { tap, numberFrames, flags, bufferListInOut, numberFramesOut, flagsOut in
             var timeRange = CMTimeRange.zero
             let status = MTAudioProcessingTapGetSourceAudio(tap,
                                                                    numberFrames,
                                                                    bufferListInOut,
                                                                    flagsOut,
                                                                    &timeRange,
                                                                    numberFramesOut)
             if noErr == status  {
                 ....
             }
         })
     var tap: Unmanaged<MTAudioProcessingTap>?
     let status = MTAudioProcessingTapCreate(kCFAllocatorDefault,
                                                                             &callbacks,
                                                                              kMTAudioProcessingTapCreationFlag_PostEffects,
                                                                             &tap)

     guard noErr == status else {
         return
     }
     inputParameter.audioTapProcessor = tap?.takeUnretainedValue()
     audioMixParameters.append(inputParameter)
     tap?.release()
}
audioMix.inputParameters = audioMixParameters
return audioMix

Replies

More information.