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 NameTypeDescription
configAsleep.ConfigAsleep.Config 객체를 입력
delegateAsleepSleepTrackingManagerDelegate결과와 에러를 받을 Delegate을 전달

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)
}
  1. didCreate()
    tracking이 생성됩니다.

  2. didUpload()
    오디오 데이터가 업로드됩니다.

    Property NameTypeDescription
    sequenceIntepoch의 순서
  3. didClose()
    tracking이 종료됩니다.

    Property NameTypeDescription
    sessionIdStringReport 결과 조회를 위한 id 값
  4. didFail()
    에러로 인해 tracking이 종료됩니다

    Property NameTypeDescription
    errorAsleep.AsleepErrorError Codes
  5. didInterrupt()
    통화 등 interrupt가 발생하여 tracking이 중단됩니다.

  6. didResume()
    interrupt 요인이 사라져 tracking이 재개됩니다.

  7. micPermissionWasDenied()
    마이크 권한 없이는 tracking을 시작할 수 없습니다.

  8. analysing()
    현재까지 측정된 결과를 받아옵니다.

    Property NameTypeDescription
    sessionAsleep.Model.Session측정 중 트래킹 세션 정보



🚧

AsleepCompletableTrackingDelegate 가 추가되었습니다

기존 createSleepTrackingManager(config:delegate:)에

AsleepSleepTrackingManagerDelegate를 넘기는 방식은 그대로 동작합니다.

delegate 종류가 알림을, recordingPath가 녹음 파일을 결정합니다.

delegaterecordingPath분석 완료 알림 (didComplete)녹음 파일
AsleepSleepTrackingManagerDelegate (기존)-XX
AsleepCompletableTrackingDelegate생략 (nil)OX
AsleepCompletableTrackingDelegate폴더 URLOO

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 NameTypeDescription
configAsleep.ConfigAsleep.Config 객체를 입력
delegateAsleepCompletableTrackingDelegate결과와 에러를 받을 Delegate을 전달
recordingPathURL?녹음 파일을 저장할 폴더. 생략하거나 nil이면 녹음 파일을 만들지 않습니다. 기본값 nil
recordingTypeAsleep.RecordingType남길 녹음 종류. recordingPath가 있을 때만 적용됩니다. 기본값 .all

기존 AsleepSleepTrackingManagerDelegate를 상속하며 두 메서드가 추가됩니다.

protocol AsleepCompletableTrackingDelegate: AsleepSleepTrackingManagerDelegate {
    func didCreate(sessionId: String)
    func didComplete(session: Asleep.Model.Session)
}
  • didCreate(sessionId:) — 세션이 생성되면 세션 ID와 함께 호출됩니다. 기존 didCreate() 대신 호출되므로 didCreate()는 구현하지 않아도 됩니다.
    • sessionId: 생성된 세션 ID
  • didComplete(session:) — 측정 종료 후 서버 분석이 끝나 결과를 조회할 수 있을 때 호출됩니다.
    • session: 분석이 완료된 세션. sleepStages 등으로 바로 결과를 표시할 수 있고, 통계(stat)까지 필요하면 Reports.report(sessionId:)를 호출하세요.

그 외 메서드(didUpload, didClose, didFail, didInterrupt, didResume, micPermissionWasDenied, analysing)는 기존과 같습니다.


종료 후 분석 완료까지

stopTracking()을 호출하면 SDK는 세션을 먼저 종료한 뒤, 분석이 끝났는지 주기적으로 확인합니다.

stopTracking()
  │
  ├ ① 세션 종료 요청
  │     성공 → didClose(sessionId:)
  │
  ├ ② 분석 완료 확인 (3초 간격 · 최대 10회, 약 30초)
  │
  ├ ③-a 분석 완료 → didComplete(session:)
  │
  └ ③-b 30초 안에 끝나지 않음 → didFail(error: .completeTimeout)
⚠️

completeTimeout은 측정 실패가 아닙니다. 세션은 이미 정상 종료되었고, 분석이 30초 안에 끝나지 않았다는 뜻입니다. 잠시 후 Reports.report(sessionId:)로 결과를 조회하세요.

세션 종료 요청 자체가 실패하면 didFail(error:)만 호출되고, didClose와 분석 완료 확인은 진행되지 않습니다.


녹음 파일 저장 (선택)

recordingPath를 지정하면 측정 중 오디오를 30초 단위로 임시 저장하고, 분석이 완료되면 분석 결과를 기준으로 코골이 · 호흡 불안정 구간 파일만 골라 {recordingPath}/audio/{sessionId}/에 남깁니다.

항목내용
남기는 파일코골이 감지 구간 중 강도 상위 10개 + 호흡 불안정 감지 구간 중 심각도 상위 10개
파일 형식M4A (AAC), 16kHz, 모노, 30초
보관 세션 수최근 7개 (넘으면 오래된 세션부터 삭제)
백업iCloud / iTunes 백업에서 제외
저장 공간측정 시작 시 여유 공간이 200MB 미만이면 didFail(error: .insufficientStorage)을 호출하고 측정을 시작하지 않습니다. 측정 중 10MB 미만이 되면 파일 저장만 건너뛰고 측정은 계속합니다

Asleep.RecordingType

enum RecordingType {
    case all          // 코골이 + 호흡 불안정 (기본값)
    case snoringOnly  // 코골이 구간만
    case breathOnly   // 호흡 불안정 구간만
}
  • 플랜에서 제공하지 않는 지표의 녹음은 recordingType으로 켜지 않습니다. 플랜 범위 안에서 종류를 좁히는 용도입니다.
  • 분석 완료를 받지 못한 경우(completeTimeout), .all은 측정 중 저장한 파일을 고르지 않고 모두 남기고, .snoringOnly / .breathOnly는 아무것도 남기지 않습니다.
  • 측정 시간이 너무 짧은 경우 등 분석 결과를 쓸 수 없는 세션은 녹음 파일을 남기지 않습니다.

Asleep.createRecordingFileManager()

저장된 녹음 파일을 조회하거나 삭제합니다. createSleepTrackingManager에 넘긴 것과 같은 recordingPath를 넘겨야 합니다. 다른 경로를 넘기면 조회 결과가 비어 있습니다.

let fileManager = Asleep.createRecordingFileManager(recordingPath: recordingPath)

// [String]
let sessionIds = fileManager.getSessions()

// 코골이 파일 (강도 높은 순)                          
let snoringFiles = fileManager.getSnoringFiles(sessionId: sessionId)  

// 호흡 불안정 파일 (심각도 높은 순)
let breathFiles = fileManager.getBreathFiles(sessionId: sessionId)

// 전체 30초 구간 (구간 번호 순)    
let segments = fileManager.getAllSegments(sessionId: sessionId)       

try fileManager.deleteSession(sessionId: sessionId)
try fileManager.deleteAllSessions()
// Asleep.Model.RecordingFile
struct RecordingFile {
    let filePath: URL?          // 파일이 저장되지 않은 구간은 nil
    let segmentIndex: Int       // 30초 구간 번호
    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)
}

🚧

SDK-클라이언트 동시 녹음이 필요한 경우에만 사용

이 함수는 iOS에서 하나의 Audio Session만 사용하는 애플 권장 사항을 따르면서,
SDK와 클라이언트가 동시에 오디오를 다뤄야 하는 상황에서도 안정적으로 녹음 데이터를 제공하기 위해 사용됩니다.
특히 InputNode 레벨에서 PCM 데이터를 클라이언트 측으로 실시간 전달할 수 있도록 설계되었습니다.


Start sleep tracking

Asleep.SleepTrackingManager.startTracking()

var manager: Asleep.SleepTrackingManager?
manager?.startTracking()
🚧

수면 측정 테스트 시 안내 사항을 따라주시기 바랍니다.

Asleep의 수면 측정/분석 기능을 정확하게 테스트하려면, 
테스트 환경 가이드를 반드시 따라주시기 바랍니다. 이 가이드를 준수하지 않은 환경에서 얻은 수면 분석 결과는 
실제 수면 패턴과 정확하게 일치하지 않을 수 있음을 유의해주세요.

🔗 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()

분석 구간 지정 (v3.3.0)

측정을 종료할 때 서버가 분석할 구간(시작 · 종료 시각)을 직접 지정할 수 있습니다. 예를 들어 사용자가 입력한 “잠든 시각 ~ 일어난 시각”만 분석할 때 사용합니다.

var manager: Asleep.SleepTrackingManager?

// 측정 전체 분석 (기존)
manager?.stopTracking()

// 지정한 구간만 분석
manager?.stopTracking(analysisStartTime: analysisStartTime,
                      analysisEndTime: analysisEndTime)
Property NameTypeDescription
analysisStartTimeDate분석 시작 시각
analysisEndTimeDate분석 종료 시각. analysisStartTime보다 늦어야 합니다
  • 두 값은 항상 함께 넘깁니다. 구간 없이 종료하려면 stopTracking()을 호출하세요.
  • 종료 이후 흐름(didClose → didComplete)은 구간을 지정하지 않았을 때와 같습니다.

구간을 지정하면 달라지는 점

항목변화
sleepStages / breathStages / snoringStages지정한 구간만큼만 내려옵니다
Session.startTime / endTime분석 구간의 시작 · 종료 시각
Session.measurementStartTime / measurementEndTime실제로 측정(녹음)이 시작 · 종료된 시각
Report.analysis분석한 구간 정보 (Reports 페이지 참고)
녹음 파일 (recordingPath 지정 시)분석 구간 안에서 파일을 고릅니다

잘못된 구간을 넘겼을 때

구간이 잘못되었더라도 세션이 열린 채로 남지 않도록, SDK는 구간 없이 세션을 종료합니다.

상황동작
시작 시각이 종료 시각보다 늦거나 같음didFail(error: .invalidParameter)를 호출한 뒤 구간 없이 세션을 종료합니다. 이후 didClose → didComplete는 정상으로 진행됩니다
서버가 구간을 거부SDK가 구간 없이 다시 종료를 요청합니다. 성공하면 정상 흐름으로 진행되며, 앱에는 별도로 알리지 않습니다
종료 요청 자체가 실패기존과 같이 didFail(error:)

구간이 실제로 적용되었는지는 결과의 Report.analysis를 보거나, Session.startTime과 measurementStartTime을 비교해 확인할 수 있습니다.



Get sleep tracking status

Asleep.SleepTrackingManager.getTrackingStatus()

var manager: Asleep.SleepTrackingManager?
let trackingStatus = manager?.getTrackingStatus()

Resume tracking

Asleep.SleepTrackingManager.resumeTracking()

  • 수면측정 중 cannotActivateInBackground 오류가 발생하였을 경우 사용자에게 notification 등으로 알리고 앱을 foreground 상태에서 Asleep.SleepTrackingManager.resumeTracking()을 실행하여야 함.
var manager: Asleep.SleepTrackingManager?
manager?.resumeTracking()

Data Type

Asleep.SleepTrackingManager.TrackingStatus

struct TrackingStatus {
    var sessionId: String?
}
Property nameTypeDescription
sessionIdString?현재 Tracking 중인 session id
AsleepSleepTrackingManagerDelegate의 didCreate 함수에서
부터 사용할수 있으며 해당 Session이 Close 될때 까지 유요하다

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 nameTypeDescriptionVersion
idString수면 세션 ID
stateAsleep.Model.State수면 세션 상태 (OPEN, CLOSED, or COMPLETE)
startTimeDate세션 시작 시각. 분석 구간이 지정된 경우 분석 구간의 시작 시각
endTimeDate?세션 종료 시각. 분석 구간이 지정된 경우 분석 구간의 종료 시각
unexpectedEndTimeDate?비정상 세션 종료 시각. 앱 크래시 등으로 세션이 정상적으로 진행 및 종료되지 못했을 경우, 나중에 클라이언트가 initConfig 를 실행하여 세션을 종료시킨 시각이 기록됨. 이 경우 end_time은 마지막까지 업로드된 오디오 파일의 순서 번호를 기준으로 계산됨. 따라서 nil이 아닐 경우 비정상 세션.
measurementStartTimeDate?분석 구간과 관계없이 실제로 측정(녹음)이 시작된 시각v3.3.0
measurementEndTimeDate?분석 구간과 관계없이 실제로 측정(녹음)이 종료된 시각v3.3.0
createdTimezoneString세션이 생성된 타임존 (Timezone List)
sleepStagesArray<Int>수면 단계 리스트
-1: error (invalid audio, analysis error, etc)
0 : wake
1 : light
2 : deep
3 : rem
breathStagesArray<Int>호흡 안정성 리스트
snoringStagesArray<Int>코골이 리스트
-1: error (invalid audio, analysis error, etc)
0 : no snoring
1 : snoring
sleepStageProbs[[Float]]?각 epoch의 수면 단계 확률값 리스트
breathStageProbs[[Float]]?각 epoch의 호흡 안정성 확률값 리스트
snoringStageProbs[[Float]]?각 epoch의 코골이 확률값 리스트

Did this page help you?