最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

ios - Voice recording WatchOS application gets closed after several hours - Stack Overflow

programmeradmin1浏览0评论

I have developed a WatchOS app that records the voice while user is sleeping. I have noticed that this app is getting closed after several hours. How can I prevent this?

PS. The app can be running on the user's iPhone at the same time as user Apple watc, in case app running on iPhone could somehow prevent this.

Full code for audio recorder part:

import SwiftUI
import AVFoundation
import WatchKit
import CryptoKit

class AudioRecorder: NSObject, ObservableObject, AVAudioRecorderDelegate {
    @Published var isRecording = false
    @Published var recordings: [Recording] = []

    private var audioRecorder: AVAudioRecorder?
    private var currentRecordingURL: URL?
    private var encryptionKey : SymmetricKey = SymmetricKey(size: .bits256)
    private var audioBuffer: Data = Data()
    private let bufferSizeThreshold = 4096

    private var recordingTimer: Timer?
    private let recordingChunkDuration: TimeInterval = 10
    private let pauseDuration: TimeInterval = 5
    
    private var audioSessionInitialized = false // Flag to track session setup

    override init(){
        super.init()
        recordings = loadRecordings()
        encryptionKey = getEncryptionKey()
    }
    
   func startRecording() {
       setupAudioSession()  // Ensure session is set up before recording


       let fileManager = FileManager.default
       let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
       let dateFormatter = DateFormatter()
       dateFormatter.dateFormat = "yyyyMMdd_HHmmss"
       let recordingName = dateFormatter.string(from: Date()) + ".m4a"
       currentRecordingURL = documentsDirectory.appendingPathComponent(recordingName)

       let settings: [String: Any] = [
           AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
           AVSampleRateKey: 22050.0,
           AVNumberOfChannelsKey: 1,
           AVEncoderAudioQualityKey: AVAudioQuality.min.rawValue
       ]

       do {
           audioRecorder = try AVAudioRecorder(url: currentRecordingURL!, settings: settings)
           audioRecorder?.delegate = self
           // Remove intermittent recording for now to simplify debugging
           audioRecorder?.record() // Record continuously instead of in chunks
           isRecording = true

           print("Started recording to:", currentRecordingURL!) // Debug print
       } catch {
           print("Error starting recording:", error)
           isRecording = false
       }
   }

   private func setupAudioSession() {
       do {
           let audioSession = AVAudioSession.sharedInstance()
           // Specify .record for recording-only
           //
           // [.mixWithOthers, .defaultToSpeaker] .defaultToSpeaker is unavailablke in WatchOS:
           try audioSession.setCategory(.playAndRecord, mode: .default, options: [.mixWithOthers]) //
           try audioSession.setActive(true)
           
           print("Audio session activated.")
       } catch {
           print("Error setting up audio session:", error)
       }
   }

    func stopRecording() {
        audioRecorder?.stop()
        isRecording = false
        currentRecordingURL = nil
        audioBuffer = Data()
    }


    func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
        guard flag else { return }
        
        let tempURL = recorder.url
        let encryptionEnabled = UserDefaults.standard.bool(forKey: "encryptionEnabled")
        
        do {
            if encryptionEnabled {
                let data = try Data(contentsOf: tempURL)
                let encryptedData = try ChaChaPoly.seal(data, using: encryptionKey)bined
                
                let encryptedFileName = "encrypted_\(tempURL.lastPathComponent)"
                let encryptedURL = tempURL.deletingLastPathComponent().appendingPathComponent(encryptedFileName)
                
                try encryptedData.write(to: encryptedURL)
                
                DispatchQueue.main.async {
                    self.recordings.insert(Recording(url: encryptedURL, createdAt: Date()), at: 0)
                }
                
                try FileManager.default.removeItem(at: tempURL)
            } else {
                DispatchQueue.main.async {
                    self.recordings.insert(Recording(url: tempURL, createdAt: Date()), at: 0)
                }
            }
        } catch {
            print("Failed to process recording:", error)
        }
    }

    func getDecryptedData(from url: URL) throws -> Data? {
        let fileData = try Data(contentsOf: url)

        if url.lastPathComponent.hasPrefix("encrypted_") {
            let sealedBox = try ChaChaPoly.SealedBox(combined: fileData)
            let decryptedData = try ChaChaPoly.open(sealedBox, using: encryptionKey)
            return decryptedData
        } else {
            return fileData
        }
    }
    
    func loadRecordings() -> [Recording] {
        let fileManager = FileManager.default
        let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
        do {
            let files = try fileManager.contentsOfDirectory(at: documentsDirectory, includingPropertiesForKeys: nil)
            let recordingFiles = files.filter { $0.pathExtension == "m4a" }
            return recordingFiles.map { fileURL in
                let attributes = try? fileManager.attributesOfItem(atPath: fileURL.path)
                let createdAt = attributes?[.creationDate] as? Date ?? Date()
                return Recording(url: fileURL, createdAt: createdAt)
            }.sorted(by: { $0.createdAt > $1.createdAt })
        } catch {
            print("Error loading recordings: \(error)")
            return []
        }
    }
    
    func getEncryptionKey() -> SymmetricKey {
        let keychainKey = "ziziapps.guardianangel.encryptionKey"
        let keychainHelper = KeychainHelper()
        if let keyData = keychainHelper.read(key: keychainKey) {
            return SymmetricKey(data: keyData)
        } else {
            // Generate a new key if one doesn't exist, then store it
            let newKey = SymmetricKey(size: .bits256)
            let keyData = newKey.withUnsafeBytes { Data($0) }
            keychainHelper.save(keyData, key: keychainKey)
            return newKey
        }
    }
}

发布评论

评论列表(0)

  1. 暂无评论