The three engineering constraints that define overnight audio on iOS
Building an audio app that runs all night on an iPhone is not about picking the right model. It is about surviving three constraints that do not exist in normal app development:
- The background task budget. iOS grants roughly 30 seconds of background runtime per activation. To run all night, the app must renew its assertion on a cadence shorter than the budget — or the OS throttles the audio queue and the night goes silent.
-
The microphone sharing policy. If another system service is using the mic, the app's
AVAudioSessionis interrupted. Over an eight-hour window, this is guaranteed to happen — and silent interruptions look exactly like quiet sleep stages. - The thermal ceiling. A sustained classifier that keeps a core warm all night triggers thermal throttling. On older devices, the phone will downclock aggressively mid-session, dropping windows of audio that the app then has to detect and flag as low-confidence.
These three constraints map directly onto the user experience: if you handle them honestly, the app returns an honest night with honest gaps. If you ignore them, the app returns a fabricated night that looks complete.
Budget renewal done right
The renewal handler must be cheap and fast, because it runs under the expiry deadline. The correct shape:
bgTask = UIApplication.shared.beginBackgroundTask { [weak self] in
self?.flushPendingBuffers() // finish the in-flight window only
self?.signalLowConfidence() // mark the tail of the night
UIApplication.shared.endBackgroundTask(bgTask)
}
The renewal itself (scheduling the next window) happens in the main audio callback, not in the expiry handler. The expiry handler only closes the current buffer cleanly. This is the exact problem the SleepTrace audio engineering notes walk through, including the drift-corrected timestamp anchoring used to avoid the gaps becoming data-integrity lies.
Microphone interruptions are features, not bugs
An interruption fires AVAudioSession.interruptionNotification. The naive response is to resume immediately. The correct response is to log the gap and lower confidence on the surrounding windows, because the microphone may have switched devices or picked up a different sound field after reconnection. Users get a morning note: "confidence reduced from 01:23–01:25 — likely a mic handoff." That is the honest signal-quality view an overnight app needs.
Thermal-aware scheduling
The classifier runs in a DispatchQueue whose qualityOfService degrades when the device reports thermal state .serious or worse. The fallback is to halve the window rate and widen the smoothing window, preserving event-level counts at the cost of temporal precision. The alternative — pushing through and getting throttled — corrupts the night with zeros that look like silence.
The user-facing payoff
Handled correctly, the morning summary reads like a careful witness instead of a confident liar:
- It shows the gaps.
- It flags the thermal-throttled regions.
- It tells you which events crossed the confidence threshold and which skimmed it.
That honesty is what earns the place on the nightstand. SleepTrace is architected entirely around treating these constraints as product requirements, not bugs to ship through.
Top comments (0)