I Messaggi Vocali nelle App Moderne

L'invio di note vocali è diventato il metodo di comunicazione più utilizzato nelle app di messaggistica. Per creare un'esperienza fluida senza blocchi dell'interfaccia (lag o freeze), occorre eseguire la registrazione in un thread prioritario e convertire l'audio istantaneamente in formato M4A con codec AAC compresso.

Codice Pratico: Voice Recorder con Estrazione Livelli Decibel in SwiftUI

import SwiftUI
import AVFoundation

@Observable
final class VoiceNoteRecorder: NSObject, AVAudioRecorderDelegate {
    var isRecording: Bool = false
    var audioLevels: [CGFloat] = []
    var duration: TimeInterval = 0
    
    private var audioRecorder: AVAudioRecorder?
    private var timer: Timer?
    private(set) var recordedFileURL: URL?
    
    func startRecording() {
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker, .allowBluetooth])
            try audioSession.setActive(true)
            
            let tempDir = FileManager.default.temporaryDirectory
            let fileURL = tempDir.appendingPathComponent("voice_note_\(UUID().uuidString).m4a")
            self.recordedFileURL = fileURL
            
            let settings: [String: Any] = [
                AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
                AVSampleRateKey: 24000.0,
                AVNumberOfChannelsKey: 1,
                AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue,
                AVEncoderBitRateKey: 32000 // 32kbps: qualità ottima per voce con peso minimo
            ]
            
            audioRecorder = try AVAudioRecorder(url: fileURL, settings: settings)
            audioRecorder?.delegate = self
            audioRecorder?.isMeteringEnabled = true
            audioRecorder?.record()
            
            isRecording = true
            audioLevels.removeAll()
            
            // Monitora i livelli ogni 50ms per disegnare la waveform
            timer = Timer.scheduledTimer(withTimeInterval: 0.05, repeats: true) { [weak self] _ in
                guard let self = self, let recorder = self.audioRecorder, recorder.isRecording else { return }
                recorder.updateMeters()
                let decibels = recorder.averagePower(forChannel: 0)
                // Normalizza da [-60dB, 0dB] a [0.1, 1.0]
                let level = max(0.1, CGFloat((decibels + 60) / 60))
                self.audioLevels.append(level)
                self.duration = recorder.currentTime
            }
        } catch {
            print("Impossibile avviare registrazione audio: \(error.localizedDescription)")
        }
    }
    
    func stopRecording() -> URL? {
        timer?.invalidate()
        timer = nil
        audioRecorder?.stop()
        isRecording = false
        return recordedFileURL
    }
}

struct WaveformBarView: View {
    let levels: [CGFloat]
    
    var body: some View {
        HStack(spacing: 3) {
            ForEach(Array(levels.suffix(40).enumerated()), id: \.offset) { _, level in
                RoundedRectangle(cornerRadius: 2)
                    .fill(Color.orange)
                    .frame(width: 3, height: max(4, level * 36))
            }
        }
        .frame(height: 40)
    }
}

Vuoi creare la tua App o hai bisogno di consulenza personalizzata?

Sviluppo app iOS native in SwiftUI, piattaforme backend scalabili e offro supporto strategico per monetizzazione e progetti internazionali.

Diallo Yunus

Diallo Yunus

Indie iOS & macOS Developer, Fondatore di DialloDev e autore di 11+ app pubblicate su Apple App Store. Aiuto startup, creator e aziende a costruire prodotti digitali di successo.