fixes
This commit is contained in:
parent
80b6835dc7
commit
3cfcf026d7
2 changed files with 17 additions and 5 deletions
|
|
@ -89,6 +89,7 @@ class AudioPlayer: NSObject, ObservableObject {
|
|||
private var offlineVisBuffer = VisFrameBuffer.empty
|
||||
private var offlineVisTimer: Timer?
|
||||
private var offlineVisFPS: Double = 30.0
|
||||
private var analysisTask: Task<Void, Never>?
|
||||
#endif
|
||||
|
||||
// MARK: - Now Playing Artwork
|
||||
|
|
@ -133,11 +134,14 @@ class AudioPlayer: NSObject, ObservableObject {
|
|||
private func suspendVisTimers() {
|
||||
stopOfflineVisTimer()
|
||||
stopLevelTimer()
|
||||
// Remove the periodic time observer — it fires at 10Hz updating @Published currentTime,
|
||||
// which triggers SwiftUI re-evaluation of the entire view tree in background.
|
||||
// This is the primary driver of the 93% background CPU that kills the process.
|
||||
// Cancel any in-progress offline vis analysis — it's a CPU-intensive FFT
|
||||
// loop that will otherwise run to completion in background, burning ~60% CPU
|
||||
analysisTask?.cancel()
|
||||
analysisTask = nil
|
||||
// Remove the periodic time observer — it fires at 10Hz updating @Published
|
||||
// currentTime, driving SwiftUI re-evaluation of the entire view tree in background
|
||||
removeTimeObserver()
|
||||
alog("Background: timers + time observer suspended")
|
||||
alog("Background: timers + time observer + analysis task suspended")
|
||||
}
|
||||
|
||||
private func resumeVisTimers() {
|
||||
|
|
@ -1231,7 +1235,8 @@ class AudioPlayer: NSObject, ObservableObject {
|
|||
let points = VisualizerSettings.shared.nowPlaying.numberOfPoints
|
||||
let cutoff = VisualizerSettings.shared.frequencyCutoff
|
||||
|
||||
Task {
|
||||
analysisTask?.cancel() // cancel any in-flight analysis from the previous song
|
||||
analysisTask = Task {
|
||||
let storage = VisualizerStorageManager.shared
|
||||
let hasCache = await storage.hasCache(for: songId)
|
||||
|
||||
|
|
@ -1504,6 +1509,8 @@ class AudioPlayer: NSObject, ObservableObject {
|
|||
nowPlayingSyncTimer = nil
|
||||
#if os(iOS)
|
||||
stopOfflineVisTimer()
|
||||
analysisTask?.cancel()
|
||||
analysisTask = nil
|
||||
if isUsingCrossfade {
|
||||
SmartCrossfadeManager.shared.stop()
|
||||
isUsingCrossfade = false
|
||||
|
|
|
|||
|
|
@ -104,6 +104,9 @@ actor OfflineAudioAnalyzer {
|
|||
var nextFrameSample = 0 // the audio sample index at which to take the next vis frame
|
||||
|
||||
while file.framePosition < totalFrames {
|
||||
// Cooperatively cancel if the app backgrounded mid-analysis
|
||||
try Task.checkCancellation()
|
||||
|
||||
let toRead = min(AVAudioFrameCount(readChunkSamples),
|
||||
AVAudioFrameCount(totalFrames - file.framePosition))
|
||||
readBuffer.frameLength = 0
|
||||
|
|
@ -138,6 +141,8 @@ actor OfflineAudioAnalyzer {
|
|||
let chunkEnd = chunkStart + chunkLen
|
||||
|
||||
while nextFrameSample < chunkEnd {
|
||||
// Check cancellation every frame — the inner loop is the hot path
|
||||
try Task.checkCancellation()
|
||||
// We need fftSize samples ending at nextFrameSample + fftSize/2
|
||||
// (centre the FFT window on the frame position for better transient response)
|
||||
let windowStart = nextFrameSample - fftSize / 2
|
||||
|
|
|
|||
Loading…
Reference in a new issue