     bufferListInOut: UnsafeMutablePointer<AudioBufferList>,
     numberFramesOut: UnsafeMutablePointer<CMItemCount>,
     flagsOut: UnsafeMutablePointer<MTAudioProcessingTapFlags>
-    ) {
-    let status = MTAudioProcessingTapGetSourceAudio(tap, numberFrames, bufferListInOut, flagsOut, nil, numberFramesOut)
-    print("get audio: \(status)\n")
-    print(tap, numberFrames, flags, bufferListInOut, numberFramesOut, flagsOut)
+) {
+    let context = bridgeUnretained(from: MTAudioProcessingTapGetStorage(tap)) as AVAudioTapProcessorContext<Player>
+    var status: OSStatus = noErr
+    defer {
+        if status != noErr {
+            MTAudioProcessingTapGetSourceAudio(tap, numberFrames, bufferListInOut, flagsOut, nil, numberFramesOut)
+        }
+    }
+    if let audioUnit = context.audioUnit {
+        var timeStamp = AudioTimeStamp()
+        timeStamp.mSampleTime = context.sampleCount
+        timeStamp.mFlags = .sampleTimeValid
+
+        status = AudioUnitRender(
+            audioUnit, nil, &timeStamp, 0, UInt32(numberFrames), bufferListInOut)
+        guard status == noErr else { return }
+
+        context.sampleCount += Float64(numberFrames)
+        numberFramesOut.pointee = numberFrames
+    }
 }
+
+//MARK: - AURenderCallback
+private func auRenderCallback(
+    inRefCon: UnsafeMutableRawPointer,
+    ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>,
+    inTimeStamp: UnsafePointer<AudioTimeStamp>,
+    inBusNumber: UInt32,
+    inNumberFrames: UInt32,
+    ioData: UnsafeMutablePointer<AudioBufferList>?
+) -> OSStatus {
+    return MTAudioProcessingTapGetSourceAudio(bridgeUnretained(from: inRefCon), CMItemCount(inNumberFrames), ioData!, nil, nil, nil)
+}
+
+//MARK: - helper
+
+private func bridge<T: AnyObject>(to obj: T) -> UnsafeMutableRawPointer {
+    return UnsafeMutableRawPointer(Unmanaged.passRetained(obj).toOpaque())
+}
+
+private func bridgeUnretained<T: AnyObject>(from pointer: UnsafeMutableRawPointer) -> T {
+    return Unmanaged<T>.fromOpaque(UnsafeRawPointer(pointer)).takeUnretainedValue()
+}
+
+private func bridgeUnretained<T: AnyObject>(to obj: T) -> UnsafeMutableRawPointer {
+    return UnsafeMutableRawPointer(Unmanaged.passUnretained(obj).toOpaque())
+}

        process: process)
}

//MARK: callbacks
private func initialize(
    tap: MTAudioProcessingTap,
    info: UnsafeMutableRawPointer?,
    storageOut: UnsafeMutablePointer<UnsafeMutableRawPointer?>
    ) {

}


private func finalize(tap: MTAudioProcessingTap) {

}


private func prepare(
    tap: MTAudioProcessingTap,
    maxFrames: CMItemCount,
    processingFormat: UnsafePointer<AudioStreamBasicDescription>
    ) {

}




import Foundation
import MediaToolbox
import CoreAudio


class AVAudioTapProcessorContext<T> {
    var supportedTapProcessingFormat: Bool = false
    var isNonInterleaved: Bool = false
    var sampleRate: Float64 = .nan
    var audioUnit: AudioUnit?
    var sampleCount: Float64 = 0
    var leftChannelVolume: Float = 0.0
    var rightChannelVolume: Float = 0.0
    var `self`: T?
}


func AudioProcessingTapCallbacks() -> MTAudioProcessingTapCallbacks {
