import Foundation import AVFoundation import Combine /// Detects system environment issues before starting a recording. /// Checks background audio, media volume, and microphone permissions. @Observable final class RecordingEnvironmentDetector { // MARK: - Published Warnings var isOtherAudioPlaying: Bool = false var isVolumeTooHigh: Bool = false var micPermissionStatus: AVAudioSession.RecordPermission = .undetermined /// List of human-readable warnings based on current environment state. var activeWarnings: [String] = [] init() { checkEnvironment() // Listen to volume changes or other audio notifications if necessary NotificationCenter.default.addObserver( self, selector: #selector(handleAudioRouteChanged), name: AVAudioSession.routeChangeNotification, object: nil ) } /// Runs environment checks and updates warnings. func checkEnvironment() { let session = AVAudioSession.sharedInstance() // 1. Check if other audio is playing in the background self.isOtherAudioPlaying = session.isOtherAudioPlaying // 2. Check if output volume is too high (above 70%) self.isVolumeTooHigh = session.outputVolume > 0.7 // 3. Check microphone permission status self.micPermissionStatus = session.recordPermission // Compile warning strings var warnings: [String] = [] if isOtherAudioPlaying { warnings.append("⚠️ 检测到后台有其他音频播放中,建议关闭以防混入录音。") } if isVolumeTooHigh { warnings.append("⚠️ 系统媒体音量过高 (%.0f%%),录音时建议降低音量。" .replacingOccurrences(of: "%.0f%%", with: String(format: "%.0f%%", session.outputVolume * 100))) } if micPermissionStatus == .denied { warnings.append("⚠️ 麦克风访问权限被禁用,请前往系统设置开启麦克风。") } self.activeWarnings = warnings } @objc private func handleAudioRouteChanged() { // Run checks on background thread to avoid blocking main loop, then dispatch updates DispatchQueue.main.async { [weak self] in self?.checkEnvironment() } } }