// // AudioRecordService.swift // AutoCatCore // // Created by Selim Mustafaev on 11.03.2025. // Copyright © 2025 Selim Mustafaev. All rights reserved. // import AVFoundation import Speech public final class AudioRecordService { let audioFileSettings: [String : Any] = [ AVFormatIDKey: kAudioFormatMPEG4AAC, AVSampleRateKey: 44100, AVNumberOfChannelsKey: 2, ] var recorder: AVAudioRecorder? public init() { } @discardableResult func requestRecognitionAuthorization() async -> SFSpeechRecognizerAuthorizationStatus { let status = SFSpeechRecognizer.authorizationStatus() guard status == .notDetermined else { return status } return await withCheckedContinuation { continuation in SFSpeechRecognizer.requestAuthorization { status in continuation.resume(returning: status) } } } } extension AudioRecordService: AudioRecordServiceProtocol { public func requestPermissions() async -> Bool { await requestRecognitionAuthorization() return await AVAudioApplication.requestRecordPermission() } public func startRecording(to url: URL) async throws { guard AVAudioApplication.shared.recordPermission != .denied else { throw AudioRecordError.permissionDenied } switch AVAudioApplication.shared.recordPermission { case .denied: throw AudioRecordError.permissionDenied case .undetermined: if await AVAudioApplication.requestRecordPermission() { break } else { return } case .granted: break @unknown default: throw AudioRecordError.unknown } try AVAudioSession.sharedInstance().setCategory(.playAndRecord) try AVAudioSession.sharedInstance().setActive(true) recorder = try AVAudioRecorder(url: url, settings: audioFileSettings) recorder?.record() } public func stopRecording() { recorder?.stop() recorder = nil } public func recognizeText(from url: URL) async -> String? { guard let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "ru-RU")), recognizer.isAvailable else { return nil } let request = SFSpeechURLRecognitionRequest(url: url) return await withCheckedContinuation { continuation in recognizer.recognitionTask(with: request) { result, error in continuation.resume(returning: result?.bestTranscription.formattedString) } } } }