 
 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 {

        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>
    ) {

}



    bufferListInOut: UnsafeMutablePointer<AudioBufferList>,
    numberFramesOut: UnsafeMutablePointer<CMItemCount>,
    flagsOut: UnsafeMutablePointer<MTAudioProcessingTapFlags>
) {
    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())
}
