SleepTrackingManager
Create manager
Asleep.createSleepTrackingManager()
var config: Asleep.Config?
let delegate: AsleepSleepTrackingManagerDelegate = self
var manager: Asleep.SleepTrackingManager?
if let config {
manager = Asleep.createSleepTrackingManager(config: config,
delegate: delegate)
}| Property Name | Type | Description |
|---|---|---|
| config | Asleep.Config | Enter the Asleep.Config instance |
| delegate | AsleepSleepTrackingManagerDelegate | Delegate to receive results and errors |
AsleepSleepTrackingManagerDelegate
protocol AsleepSleepTrackingManagerDelegate {
func didCreate()
func didUpload(sequence: Int)
func didClose(sessionId: String)
func didFail(error: Asleep.AsleepError)
func didInterrupt()
func didResume()
func micPermissionWasDenied()
func analysing(session: Asleep.Model.Session)
}-
didCreate()
Tracking is generated. -
didUpload()
Data is uploaded.Property Name Type Description sequence Int A value that starts from 0 and increases by 1 every 30 seconds -
didClose()
Tracking is terminated.Property Name Type Description sessionId String Report result id value -
didFail()
Due to error, tracking is endedProperty Name Type Description error Asleep.AsleepError Error Codes -
didInterrupt()
Tracking is interrupted due to events such as calls. -
didResume()
Tracking resumes once the interrupting factor is resolved. -
micPermissionWasDenied()
Tracking cannot be started without microphone permission. -
analysing()
Latest session dataProperty Name Type Description session Asleep.Model.Session during analysis, tracking session information
AsleepCompletableTrackingDelegatehas been addedPassing AsleepSleepTrackingManagerDelegate to the existing createSleepTrackingManager(config:delegate:) keeps working as before.
The delegate type determines the notifications, and recordingPath determines the recording files.
| delegate | recordingPath | Analysis completion notification (didComplete) | Recording file |
|---|---|---|---|
| AsleepSleepTrackingManagerDelegate (existing) | - | X | X |
| AsleepCompletableTrackingDelegate | omitted (nil) | O | X |
| AsleepCompletableTrackingDelegate | folder URL | O | O |
AsleepCompletableTrackingDelegate
var config: Asleep.Config?
let delegate: AsleepCompletableTrackingDelegate = self
let recordingPath: URL?
let recordingType: Asleep.RecordingType
var manager: Asleep.SleepTrackingManager?
if let config {
manager = Asleep.createSleepTrackingManager(config: config,
delegate: delegate,
recordingPath: recordingPath,
recordingType: recordingType)
}| Property Name | Type | Description |
|---|---|---|
| config | Asleep.Config | Enter the Asleep.Config instance |
| delegate | AsleepCompletableTrackingDelegate | Delegate to receive results and errors |
| recordingPath | URL? | The folder where recording files are saved. If it is omitted or nil, no recording file is created. Default nil |
| recordingType | Asleep.RecordingType | The type of recording to keep. Applied only when recordingPath is set. Default .all |
It inherits the existing AsleepSleepTrackingManagerDelegate and adds two methods.
protocol AsleepCompletableTrackingDelegate: AsleepSleepTrackingManagerDelegate {
func didCreate(sessionId: String)
func didComplete(session: Asleep.Model.Session)
}- didCreate(sessionId:) — Called with the session id once the session is created. It is called instead of the existing
didCreate(), so you do not need to implementdidCreate().sessionId: Generated session id
- didComplete(session:) — Called when the server analysis is finished after tracking is terminated and the result is ready to be retrieved.
session: The session whose analysis is complete. You can display the result right away withsleepStagesand so on, and callReports.report(sessionId:)if you also need the statistics (stat).
The other methods (didUpload, didClose, didFail, didInterrupt, didResume, micPermissionWasDenied, analysing) are the same as before.
From termination to analysis completion
When stopTracking() is called, the SDK closes the session first and then checks periodically whether the analysis is finished.
stopTracking()
│
├ ① Session close request
│ Success → didClose(sessionId:)
│
├ ② Analysis completion check (every 3 seconds · up to 10 times, about 30 seconds)
│
├ ③-a Analysis complete → didComplete(session:)
│
└ ③-b Not finished within 30 seconds → didFail(error: .completeTimeout)
completeTimeout is not a tracking failureThe session has already been terminated normally; it only means the analysis did not finish within 30 seconds. Retrieve the result a little later with Reports.report(sessionId:).
If the session close request itself fails, only didFail(error:) is called, and didClose and the analysis completion check do not proceed.
Saving recording files (optional)
If you set recordingPath, the audio is temporarily saved in 30-second units during tracking, and once the analysis is complete, only the snoring and unstable-breathing segment files selected based on the analysis result are kept in {recordingPath}/audio/{sessionId}/.
| Item | Description |
|---|---|
| Files kept | Top 10 by intensity among the detected snoring segments + top 10 by severity among the detected unstable-breathing segments |
| File format | M4A (AAC), 16kHz, mono, 30 seconds |
| Number of sessions kept | The 7 most recent (when exceeded, the oldest sessions are deleted first) |
| Backup | Excluded from iCloud / iTunes backup |
| Storage space | If the free space is less than 200MB when tracking starts, didFail(error: .insufficientStorage) is called and tracking does not start. If it drops below 10MB during tracking, only the file saving is skipped and tracking continues |
Asleep.RecordingType
enum RecordingType {
case all // Snoring + unstable breathing (default)
case snoringOnly // Snoring segments only
case breathOnly // Unstable-breathing segments only
}recordingTypedoes not turn on recordings for metrics that your plan does not provide. It is used to narrow the type within the scope of your plan.- If the analysis completion is not received (
completeTimeout),.allkeeps every file saved during tracking without selecting any, and.snoringOnly/.breathOnlykeep nothing. - Sessions whose analysis result cannot be used, such as when the tracking time is too short, do not keep recording files.
Asleep.createRecordingFileManager()
Retrieves or deletes the saved recording files. You must pass the same recordingPath that was passed to createSleepTrackingManager. If you pass a different path, the result is empty.
let fileManager = Asleep.createRecordingFileManager(recordingPath: recordingPath)
// [String]
let sessionIds = fileManager.getSessions()
// Snoring files (in order of intensity)
let snoringFiles = fileManager.getSnoringFiles(sessionId: sessionId)
// Unstable-breathing files (in order of severity)
let breathFiles = fileManager.getBreathFiles(sessionId: sessionId)
// All 30-second segments (in order of segment index)
let segments = fileManager.getAllSegments(sessionId: sessionId)
try fileManager.deleteSession(sessionId: sessionId)
try fileManager.deleteAllSessions()// Asleep.Model.RecordingFile
struct RecordingFile {
let filePath: URL? // nil for segments whose file was not saved
let segmentIndex: Int // 30-second segment index
let maxDb: Float
let isSnoringDetected: Bool
let isBreathDetected: Bool
let timestamp: String?
let snoreIntensity: Float
let breathSeverity: Float
}Concurrent Audio Capture (optional)
Asleep.SleepTrackingManager.setDeliveryDelegate()
let trackingManager = Asleep.createSleepTrackingManager(config: config, delegate: delegate)
trackingManager.setDeliveryDelegate(self)Asleep.AsleepAudioDeliveryManagerDelegate
protocol AsleepAudioDeliveryManagerDelegate: AnyObject {
func deliveryAudio(didReceiveRawBuffer buffer: AVAudioPCMBuffer,
at time: AVAudioTime)
}
Use only when simultaneous SDK–client recording is requiredThis function is used to comply with Apple’s recommendation of maintaining a single Audio Session in iOS,
while ensuring stable audio recording in scenarios where both the SDK and the client need to handle audio simultaneously.
It is specifically designed to deliver PCM data to the client in real time at the InputNode level.
Start sleep tracking
Asleep.SleepTrackingManager.startTracking()
var manager: Asleep.SleepTrackingManager?
manager?.startTracking()
Follow the guideline for testing the sleep trackingTo accurately test Asleep's sleep tracking/analysis, please follow the test environment guide. Please note that sleep analysis results obtained in environments not adhering to this guide may not accurately reflect actual sleep patterns.
🔗 Check Test Environment Guideline
Request the latest analyzed sleep data
Asleep.SleepTrackingManager.requestAnalysis()
var manager: Asleep.SleepTrackingManager?
manager?.requestAnalysis()Stop sleep tracking
Asleep.SleepTrackingManager.stopTracking()
var manager: Asleep.SleepTrackingManager?
manager?.stopTracking()Specifying the analysis range (v3.3.0)
When you stop tracking, you can directly specify the range (start and end time) that the server will analyze. For example, use it when you want to analyze only the "time the user fell asleep ~ time the user woke up" entered by the user.
var manager: Asleep.SleepTrackingManager?
// Analyze the whole tracking (existing)
manager?.stopTracking()
// Analyze only the specified range
manager?.stopTracking(analysisStartTime: analysisStartTime,
analysisEndTime: analysisEndTime)| Property Name | Type | Description |
|---|---|---|
| analysisStartTime | Date | Analysis start time |
| analysisEndTime | Date | Analysis end time. Must be later than analysisStartTime |
- Always pass the two values together. To terminate without a range, call
stopTracking(). - The flow after termination (
didClose→didComplete) is the same as when no range is specified.
What changes when a range is specified
| Item | Change |
|---|---|
sleepStages / breathStages / snoringStages | Only the specified range is returned |
Session.startTime / endTime | The start and end time of the analysis range |
Session.measurementStartTime / measurementEndTime | The time at which the tracking (recording) actually started and ended |
Report.analysis | Information about the analyzed range (see the Reports page) |
Recording file (when recordingPath is set) | Files are selected from within the analysis range |
When an invalid range is passed
So that the session is not left open even if the range is invalid, the SDK terminates the session without the range.
| Case | Behavior |
|---|---|
| The start time is later than or equal to the end time | didFail(error: .invalidParameter) is called, and then the session is terminated without the range. didClose → didComplete then proceed normally |
| The server rejects the range | The SDK requests the termination again without the range. If it succeeds, the normal flow proceeds and the app is not notified separately |
| The termination request itself fails | didFail(error:), same as before |
You can check whether the range was actually applied by looking at Report.analysis in the result, or by comparing Session.startTime with measurementStartTime.
Get sleep tracking status
Asleep.SleepTrackingManager.getTrackingStatus()
var manager: Asleep.SleepTrackingManager?
let trackingStatus = manager?.getTrackingStatus()Resume tracking
Asleep.SleepTrackingManager.resumeTracking()
- If a cannotActivateInBackground error occurs during sleep tracking, notify the user (e.g., through a notification), and run Asleep.SleepTrackingManager.resumeTracking() while the app is in the foreground.
var manager: Asleep.SleepTrackingManager?
manager?.resumeTracking()Data Type
Asleep.SleepTrackingManager.TrackingStatus
struct TrackingStatus {
var sessionId: String?
}| Property name | Type | Description |
|---|---|---|
| sessionId | String? | Currently tracking session id Available from the didCreate function of AsleepSleepTrackingManagerDelegate Valid until the corresponding Session is closed |
Asleep.Model.Session
struct Session {
let id: String
let state: State
let startTime: Date
let endTime: Date?
let unexpectedEndTime: Date?
let measurementStartTime: Date?
let measurementEndTime: Date?
let createdTimezone: String
let sleepStages: [Int]?
let breathStages: [Int]?
let snoringStages: [Int]?
let sleepStageProbs: [[Float]]?
let breathStageProbs: [[Float]]?
let snoringStageProbs: [[Float]]?
}
enum State {
case open
case closed
case complete
}
| Property name | Type | Description | Version |
|---|---|---|---|
| id | String | Sleep session id | |
| state | Asleep.Model.State | Sleep session state (OPEN, CLOSED, or COMPLETE) | |
| startTime | Date | Session start time. If an analysis period was specified, the start time of the analysis period | |
| endTime | Date? | Session end time. If an analysis period was specified, the end time of the analysis period | |
| unexpectedEndTime | Date? | If a session fails to proceed and terminate properly due to app crashes or similar issues, and the client later executes initConfig to terminate the session, the time at which this happens is recorded. In this case, the "end_time" is calculated based on the sequence number of the last uploaded audio file. Therefore, if "end_time" is not null, it indicates an abnormal session. | |
| measurementStartTime | Date? | The time the measurement (recording) actually started, regardless of the analysis period | v3.3.0 |
| measurementEndTime | Date? | The time the measurement (recording) actually ended, regardless of the analysis period | v3.3.0 |
| createdTimezone | String | Timezone of session creation (Timezone List) | |
| sleepStages | Array<Int> | Sleep stages-1: error0 : wake1 : light2 : deep3 : rem | |
| breathStages | Array<Int> | Breathing stability stages | |
| snoringStages | Array<Int> | Snoring stages-1: error0 : no snoring1 : snoring | |
| sleepStageProbs | [[Float]]? | Probability values of the sleep stages for each epoch | |
| breathStageProbs | [[Float]]? | Probability values of the breathing stability stages for each epoch | |
| snoringStageProbs | [[Float]]? | Probability values of the snoring stages for each epoch |
Updated 7 days ago
