Important Notes
v3.1.7부터 오디오 라우트 처리 및 세션 옵션 커스터마이징이 추가되었습니다.
Audio Route Change Handling
1. 새로운 Delegate Methods
오디오 경로 변경(블루투스 연결/해제, 헤드폰 연결 등) 시 호출되는 delegate가 추가되었습니다.
protocol AsleepSleepTrackingManagerDelegate {
// 라우트 변경 시작 (Engine 재시작 전)
func willChangeAudioRoute(from oldRoute: AVAudioSessionRouteDescription,
to newRoute: AVAudioSessionRouteDescription)
// 라우트 변경 완료 (Engine 재시작 후)
func didChangeAudioRoute(to newRoute: AVAudioSessionRouteDescription)
}특징:
- Optional 메서드 (구현하지 않아도 기존 동작 유지)
- 블루투스, 헤드폰 연결/해제 시 호출
- Engine 재구성 전후로 분리되어 호출
2. Interruption vs Route Change
| Delegate | 발생 조건 | Engine 재시작 | 처리 속도 |
|---|---|---|---|
didInterrupt() / didResume() | 전화, 알람, VOIP | 없음 | 빠름 (~수 밀리초) |
willChangeAudioRoute() / didChangeAudioRoute() | 블루투스, 헤드폰 연결/해제 | 있음 | 느림 (100-500ms) |
3. 사용 예시
음악 재생 앱
extension YourViewController: AsleepSleepTrackingManagerDelegate {
func willChangeAudioRoute(from oldRoute: AVAudioSessionRouteDescription,
to newRoute: AVAudioSessionRouteDescription) {
// 라우트 변경 시작 -> 음악 일시정지
if musicPlayer?.isPlaying == true {
musicPlayer?.pause()
}
}
func didChangeAudioRoute(to newRoute: AVAudioSessionRouteDescription) {
// 라우트 변경 완료 -> 음악 재개
musicPlayer?.play()
}
}라우트 정보 로깅
func willChangeAudioRoute(from oldRoute: AVAudioSessionRouteDescription,
to newRoute: AVAudioSessionRouteDescription) {
let oldOutput = oldRoute.outputs.first?.portType.rawValue ?? "unknown"
let newOutput = newRoute.outputs.first?.portType.rawValue ?? "unknown"
print("Audio route changing: \(oldOutput) -> \(newOutput)")
}Audio Session Options Customization
설계 목적
v3.1.7부터 SDK가 오디오 세션을 전담 관리합니다. 클라이언트가 직접 AVAudioSession.setActive() 또는 setCategory()를 호출하면 SDK와 충돌이 발생할 수 있습니다. 필요한 옵션은 startTracking()에 전달하여 SDK가 적절한 타이밍에 적용하도록 해야 합니다.
1. API 변경
startTracking() 메서드에 오디오 세션 옵션을 전달할 수 있습니다.
// 기존 (여전히 동작)
manager?.startTracking()
// 신규: 추가 옵션 전달
manager?.startTracking(additionalAudioSessionOptions: [.duckOthers])중요:
- 트래킹 중
AVAudioSession.sharedInstance().setActive()직접 호출 금지 - 트래킹 중
AVAudioSession.sharedInstance().setCategory()직접 호출 금지 - 필요한 옵션만
additionalAudioSessionOptions로 전달
2. SDK 기본 설정
SDK는 오디오 세션을 다음과 같이 설정합니다:
// Category (변경 불가)
.playAndRecord // 녹음 + 재생 동시 지원
// Options (변경 불가)
[.mixWithOthers, .allowBluetoothA2DP]additionalAudioSessionOptions에 전달한 옵션은 기본값에 추가됩니다:
manager?.startTracking(additionalAudioSessionOptions: [.duckOthers])
// 최종 적용: Category = .playAndRecord, Options = [.mixWithOthers, .allowBluetoothA2DP, .duckOthers]3. 주요 사용 사례
음악 볼륨 자동 감소
func startTrackingWithMusic() {
// 다른 앱 오디오 볼륨 자동 감소
manager?.startTracking(additionalAudioSessionOptions: [.duckOthers])
// 음악 재생
musicPlayer?.play()
}AirPlay 지원
func startTrackingWithAirPlay() {
// AirPlay 허용
manager?.startTracking(additionalAudioSessionOptions: [.allowAirPlay])
}여러 옵션 조합
manager?.startTracking(additionalAudioSessionOptions: [
.duckOthers, // 음악 볼륨 감소
.allowAirPlay // AirPlay 허용
])4. 사용 가능한 옵션
| 옵션 | 설명 | 사용 예시 |
|---|---|---|
.mixWithOthers | 다른 앱 오디오와 믹싱 (SDK 기본값) | 항상 적용됨 |
.allowBluetoothA2DP | A2DP 블루투스 허용 (SDK 기본값) | 항상 적용됨 |
.duckOthers | 다른 앱 오디오 볼륨 감소 | 음악 재생 시 방해 최소화 |
.allowAirPlay | AirPlay 허용 | HomePod 재생 |
.defaultToSpeaker | 스피커 우선 출력 | 스피커폰 사용 |
주의: .mixWithOthers는 SDK 기본값이므로 별도로 전달할 필요 없습니다.
5. 주의사항
옵션 누적:
- 매
startTracking()호출 시 새로 설정됨 - 이전 옵션은 유지되지 않음
// 첫 번째
manager?.startTracking(additionalAudioSessionOptions: [.duckOthers])
// stopTracking() 후 재시작
manager?.stopTracking()
manager?.startTracking(additionalAudioSessionOptions: [.allowAirPlay])
// -> .duckOthers는 사라지고 .allowAirPlay만 적용잘못된 사용 예시:
// [금지] 트래킹 중 직접 오디오 세션 제어
func startTracking() {
manager?.startTracking()
// SDK와 충돌 발생!
try? AVAudioSession.sharedInstance().setActive(true) // <- 하지 마세요
}Stability Improvements (v3.1.7)
1. 블루투스 안정성 개선
수정된 문제:
- 블루투스 연결/해제 시 녹음 중단
- VOIP 통화 후 녹음 재개 실패
- 블루투스 연결 중 오디오 포맷 변경 크래시
결과:
- 블루투스 기기 연결 상태 변화 시에도 안정적 녹음 유지
- 스피커 ↔ 블루투스 자동 전환
2. 인터럽션 복구 개선
자동 복구 메커니즘:
- 10초 자동 복구 타이머 추가
- 앱 포그라운드 복귀 시 자동 복구 시도
- VOIP 감지 및 대기
코드 수정 불필요:
- SDK 내부에서 자동 처리
- 기존
didResume()delegate 그대로 호출됨
3. 크래시 수정
다음 상황에서 발생하던 크래시 수정:
- 인터럽션 중 오디오 라우트 재구성
- 메모리 접근 오류
- Race condition
Migration Guide
기존 코드 (변경 불필요)
class MyViewController: UIViewController, AsleepSleepTrackingManagerDelegate {
var manager: Asleep.SleepTrackingManager?
func startTracking() {
Asleep.shared().createSleepTrackingManager(config: config, delegate: self)
manager?.startTracking() // 기존 코드 그대로 동작
}
// 기존 delegate 메서드들
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: 음악 재생 제어
extension MyViewController {
// 신규 delegate 추가 (optional)
func willChangeAudioRoute(from oldRoute: AVAudioSessionRouteDescription,
to newRoute: AVAudioSessionRouteDescription) {
if musicPlayer?.isPlaying == true {
musicPlayer?.pause()
}
}
func didChangeAudioRoute(to newRoute: AVAudioSessionRouteDescription) {
musicPlayer?.play()
}
}선택적 개선 2: 오디오 옵션 추가
extension MyViewController {
func startTrackingWithMusic() {
Asleep.shared().createSleepTrackingManager(config: config, delegate: self)
// 음악 볼륨 자동 감소
manager?.startTracking(additionalAudioSessionOptions: [.duckOthers])
// 백그라운드 음악 재생
playBackgroundMusic()
}
}Updated 1 day ago
