//
//  AudioManager.swift
//  HARKlibSample
//
//  Created by Tomoyoshi Kinoshita on 2021/04/21.
//

import Foundation
import AVFoundation

class AudioManager
{
    let session = AVAudioSession.sharedInstance()
    let engine = AVAudioEngine()
    let audioMixer = AVAudioMixerNode()
    let audioFormat: AVAudioFormat = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 16000, channels: 1, interleaved: true)!
    
    init(){
        
        do {
            try self.session.setCategory(.record, options: .defaultToSpeaker)
            try self.session.setActive(true)//, options: .notifyOthersOnDeactivation)
	
//            if let desc = self.session.availableInputs?.first(where: { (desc) -> Bool in
//                return desc.portType == .builtInMic
//            }) {
//                try self.session.setPreferredInput(desc)
//            }
            
//            self.engine.attach(self.audioMixer)
//            let micInput = self.engine.mainMixerNode
//            let micFormat = micInput.inputFormat(forBus: 0)
//            self.engine.connect(micInput, to: self.audioMixer, format: micFormat)
//
//            self.engine.connect(self.audioMixer, to: self.engine.mainMixerNode, format: self.audioFormat)
//
//            self.engine.attach(self.audioMixer)
//            self.engine.connect(self.engine.inputNode, to: self.audioMixer, format: self.engine.inputNode.outputFormat(forBus: 0))
//            self.engine.connect(self.audioMixer, to: self.engine.outputNode, format: self.audioFormat)
//            self.engine.connect(self.engine.inputNode, to: self.engine.mainMixerNode, format: self.engine.inputNode.outputFormat(forBus: 0))
//            self.engine.connect(self.engine.mainMixerNode, to: self.engine.outputNode, format: self.engine.inputNode.outputFormat(forBus: 0)) // self.audioFormat) // engine.mainMixerNode.outputFormat(forBus: 0))
            self.engine.connect(self.engine.inputNode, to: self.engine.outputNode, format: self.engine.inputNode.outputFormat(forBus: 0))

            self.engine.inputNode.volume = 1.0
            
        }catch let error {
            NSLog(error.localizedDescription)
        }
    }
    
    func prepare(handler: @escaping (_ buffer: AVAudioPCMBuffer)->Void, bufferSize: UInt32){
        let converter = AVAudioConverter(from: self.engine.inputNode.outputFormat(forBus: 0), to: self.audioFormat)!

        self.engine.inputNode.installTap(onBus: 0, bufferSize: bufferSize, format: self.engine.inputNode.outputFormat(forBus: 0)){
            buffer, _ in

            var newBufferAvailable = true

            let inputCallback: AVAudioConverterInputBlock = { inNumPackets, outStatus in
                if newBufferAvailable {
                    outStatus.pointee = .haveData
                    newBufferAvailable = false
                    return buffer
                } else {
                    outStatus.pointee = .noDataNow
                    return nil
                }
            }

            let convertedBuffer = AVAudioPCMBuffer(pcmFormat: self.audioFormat, frameCapacity: AVAudioFrameCount(self.audioFormat.sampleRate) * buffer.frameLength / AVAudioFrameCount(buffer.format.sampleRate))!

            var error: NSError?
            let status = converter.convert(to: convertedBuffer, error: &error, withInputFrom: inputCallback)
            assert(status != .error)

            handler(convertedBuffer)
        }
    }

    func start(){
        do{
            self.engine.prepare()
            try self.engine.start()
        }catch let error {
            NSLog(error.localizedDescription)
        }
    }
    
    func stop() {
        self.engine.stop()
    }
}
