// // SoundManager.swift // SodaLive // // Created by klaus on 2023/08/10. // import Foundation import AVKit class SoundManager: NSObject, ObservableObject { @Published var errorMessage = "" @Published var isShowPopup = false @Published var isLoading = false @Published var onClose = false @Published var isPlaying = false @Published var isRecording = false @Published var duration: TimeInterval = 0 var player: AVAudioPlayer! var audioRecorder: AVAudioRecorder! var startTimer: (() -> Void)? var stopTimer: (() -> Void)? func prepareRecording() { isLoading = true let audioSession = AVAudioSession.sharedInstance() do { try audioSession.setCategory(.playAndRecord, mode: .default) try audioSession.setActive(true) audioSession.requestRecordPermission() { [weak self] allowed in DispatchQueue.main.async { if !allowed { self?.errorMessage = "권한을 허용하지 않으시면 음성메시지 서비스를 이용하실 수 없습니다." self?.isShowPopup = true self?.onClose = true } } } } catch { errorMessage = "오류가 발생했습니다. 다시 시도해 주세요." isShowPopup = true onClose = true } isLoading = false } func startRecording() { let settings = [ AVFormatIDKey: Int(kAudioFormatMPEG4AAC), AVSampleRateKey: 12000, AVNumberOfChannelsKey: 1, AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue ] do { audioRecorder = try AVAudioRecorder(url: getAudioFileURL(), settings: settings) audioRecorder.record() if let startTimer = startTimer { startTimer() } isRecording = true } catch { errorMessage = "오류가 발생했습니다. 다시 시도해 주세요." isShowPopup = true } } func stopRecording() { audioRecorder.stop() audioRecorder = nil isRecording = false if let stopTimer = stopTimer { stopTimer() } prepareForPlay() } func getRecorderCurrentTime() -> TimeInterval { return audioRecorder.currentTime } func prepareForPlay(_ url: URL? = nil) { isLoading = true DispatchQueue.main.async { let audioSession = AVAudioSession.sharedInstance() do { try audioSession.setCategory(.playback, mode: .default) if let url = url { self.player = try AVAudioPlayer(data: Data(contentsOf: url)) } else { self.player = try AVAudioPlayer(contentsOf: self.getAudioFileURL()) } self.player?.volume = 1 self.player?.delegate = self self.player?.prepareToPlay() self.duration = self.player.duration } catch { self.errorMessage = "오류가 발생했습니다. 다시 시도해 주세요." self.isShowPopup = true } self.isLoading = false } } func playAudio() { player?.play() isPlaying = player.isPlaying if let startTimer = startTimer { startTimer() } } func stopAudio() { player.stop() player.currentTime = 0 isPlaying = player.isPlaying if let stopTimer = stopTimer { stopTimer() } } func getPlayerCurrentTime() -> TimeInterval { return player.currentTime } func deleteAudioFile() { do { try FileManager.default.removeItem(at: getAudioFileURL()) duration = 0 } catch { errorMessage = "오류가 발생했습니다. 다시 시도해 주세요." isShowPopup = true } } func getAudioFileURL() -> URL { return getDocumentsDirectory().appendingPathComponent("recording.m4a") } private func getDocumentsDirectory() -> URL { let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) return paths[0] } } extension SoundManager: AVAudioPlayerDelegate { func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { stopAudio() } }