I’ve developed a WatchOS app that data the voice whereas person is sleeping. I’ve observed that this app is getting closed after a number of hours. How can I stop this?
PS. The app could be operating on the person’s iPhone similtaneously person Apple watc, in case app operating on iPhone may someway stop this.
Full code for audio recorder half:
import SwiftUI
import AVFoundation
import WatchKit
import CryptoKit
class AudioRecorder: NSObject, ObservableObject, AVAudioRecorderDelegate {
@Printed var isRecording = false
@Printed var recordings: [Recording] = []
non-public var audioRecorder: AVAudioRecorder?
non-public var currentRecordingURL: URL?
non-public var encryptionKey : SymmetricKey = SymmetricKey(dimension: .bits256)
non-public var audioBuffer: Knowledge = Knowledge()
non-public let bufferSizeThreshold = 4096
non-public var recordingTimer: Timer?
non-public let recordingChunkDuration: TimeInterval = 10
non-public let pauseDuration: TimeInterval = 5
non-public var audioSessionInitialized = false // Flag to trace session setup
override init(){
tremendous.init()
recordings = loadRecordings()
encryptionKey = getEncryptionKey()
}
func startRecording() {
setupAudioSession() // Guarantee session is ready up earlier than 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 = attempt AVAudioRecorder(url: currentRecordingURL!, settings: settings)
audioRecorder?.delegate = self
// Take away intermittent recording for now to simplify debugging
audioRecorder?.document() // Report repeatedly as a substitute of in chunks
isRecording = true
print("Began recording to:", currentRecordingURL!) // Debug print
} catch {
print("Error beginning recording:", error)
isRecording = false
}
}
non-public func setupAudioSession() {
do {
let audioSession = AVAudioSession.sharedInstance()
// Specify .document for recording-only
//https://stackoverflow.com/questions/51597590/avaudiosession-configuration-to-record-and-play-with-others
// [.mixWithOthers, .defaultToSpeaker] .defaultToSpeaker is unavailablke in WatchOS:
attempt audioSession.setCategory(.playAndRecord, mode: .default, choices: [.mixWithOthers]) //
attempt audioSession.setActive(true)
print("Audio session activated.")
} catch {
print("Error establishing audio session:", error)
}
}
func stopRecording() {
audioRecorder?.cease()
isRecording = false
currentRecordingURL = nil
audioBuffer = Knowledge()
}
func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, efficiently flag: Bool) {
guard flag else { return }
let tempURL = recorder.url
let encryptionEnabled = UserDefaults.customary.bool(forKey: "encryptionEnabled")
do {
if encryptionEnabled {
let knowledge = attempt Knowledge(contentsOf: tempURL)
let encryptedData = attempt ChaChaPoly.seal(knowledge, utilizing: encryptionKey).mixed
let encryptedFileName = "encrypted_(tempURL.lastPathComponent)"
let encryptedURL = tempURL.deletingLastPathComponent().appendingPathComponent(encryptedFileName)
attempt encryptedData.write(to: encryptedURL)
DispatchQueue.major.async {
self.recordings.insert(Recording(url: encryptedURL, createdAt: Date()), at: 0)
}
attempt FileManager.default.removeItem(at: tempURL)
} else {
DispatchQueue.major.async {
self.recordings.insert(Recording(url: tempURL, createdAt: Date()), at: 0)
}
}
} catch {
print("Didn't course of recording:", error)
}
}
func getDecryptedData(from url: URL) throws -> Knowledge? {
let fileData = attempt Knowledge(contentsOf: url)
if url.lastPathComponent.hasPrefix("encrypted_") {
let sealedBox = attempt ChaChaPoly.SealedBox(mixed: fileData)
let decryptedData = attempt ChaChaPoly.open(sealedBox, utilizing: encryptionKey)
return decryptedData
} else {
return fileData
}
}
func loadRecordings() -> [Recording] {
let fileManager = FileManager.default
let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
do {
let recordsdata = attempt fileManager.contentsOfDirectory(at: documentsDirectory, includingPropertiesForKeys: nil)
let recordingFiles = recordsdata.filter { $0.pathExtension == "m4a" }
return recordingFiles.map { fileURL in
let attributes = attempt? 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.learn(key: keychainKey) {
return SymmetricKey(knowledge: keyData)
} else {
// Generate a brand new key if one would not exist, then retailer it
let newKey = SymmetricKey(dimension: .bits256)
let keyData = newKey.withUnsafeBytes { Knowledge($0) }
keychainHelper.save(keyData, key: keychainKey)
return newKey
}
}
}