// // RecorderBytesStreamHandler.swift // audio_waveforms // // Created by Ujas Majithiya on 10/04/25. // import Foundation import AVFAudio import Accelerate class RecorderBytesStreamEngine { private var audioEngine = AVAudioEngine() private var flutterChannel: FlutterMethodChannel private var paused: Bool = false private var totalFrames: AVAudioFramePosition = 0 init(channel: FlutterMethodChannel) { flutterChannel = channel } func attach(result: @escaping FlutterResult, sampleRate: Int) { let inputNode = audioEngine.inputNode inputNode.installTap(onBus: 0, bufferSize: 1024, format: nil) { (buffer, time) in if self.paused { return } if let (convertedBytes, normalizedRms) = self.convertToFlutterType(buffer) { self.totalFrames += AVAudioFramePosition(buffer.frameLength) let effectiveSampleRate = buffer.format.sampleRate > 0 ? buffer.format.sampleRate : Double(sampleRate) let duration = Double(self.totalFrames) / effectiveSampleRate let milliseconds = Int(duration * 1000) self.sendToFlutter( convertedBytes, normalizedRms: normalizedRms, milliSeconds: milliseconds ) } } do { try audioEngine.start() } catch { result(FlutterError(code: Constants.audioWaveforms, message: "Error starting Audio Engine", details: error.localizedDescription)) } } func togglePause() { paused = !paused } func detach() { totalFrames = 0 audioEngine.inputNode.removeTap(onBus: 0) audioEngine.stop() } private func convertToFlutterType(_ buffer: AVAudioPCMBuffer) -> (FlutterStandardTypedData, Double)? { guard let channelData = buffer.floatChannelData?[0] else { return nil } let frameLength = Int(buffer.frameLength) // Convert Float32 buffer to UInt8 (byte array) var audioSamples = [Float32](repeating: 0.0, count: frameLength) var sumOfSquares: Float = 0.0 for i in 0..