AVAudioSession란?
정의
An object that communicates to the system how you intend to use audio in your app.
오디오 세션을 관리하는 객체로, 앱에서 오디오 입출력 동작을 제어하는 데 사용한다.
class AVAudioSession : NSObject
특징
- 오디오 활성화 처리
- 오디오 카테고리 설정
- 오디오 모드 설정
- 오디오 라우팅 제어
- 오디오 인터럽트 처리
1. 오디오 active / deactive
앱이 오디오를 사용할 것인지 / 사용이 끝난지에 대한 설정
Audio Session Active (활성화)
- 간단히 표현하면, OS에게 앞으로 이 앱이 오디오를 쓸 것이라고 알리는 것. 오
- 앱이 사용할 오디오 옵션들을 구성한 뒤, 이 옵션을 반영하기 위해서는 오디오 세션을 활성화 해야한다
- 앱에서 Active를 요청했더라도 만약 우선순위가 더 높은 오디오 세션이 Active 되어있다면 (ex: incoming call) 앱의 active 요청은 실패한다
Audio Session Deactive (비활성화)
- OS에게 이 앱이 오디오를 다 썼다고 알리는 것. 오디오 disabled
2. 오디오 카테고리 및 모드 설정
a. 카테고리
앱이 오디오를 어떻게 사용할지에 대한 설정
- mix (함께 재생)
- interrupt (다른 오디오 소스 중단)
Category | 폰 무음모드 or Lock 상태에서 | 다른 앱 오디오와 상호작용 | input(recording)/output(playback) |
ambient | play X | mix | output only |
soloAmbient | play X | interrupt | output only |
playback | play O | interrupt | output only |
record | record O | interrupt | input only |
playAndRecord | play O record O | interrupt | input & output |
multiRoute | play O | interrupt | input & output |
b. 모드
category가 앱의 오디오 사용 목적을 나타낸다면, mode는 그 카테고리 내에서 좀 더 구체적인 사용
시나리오의 동작을 정의한다.
그렇다면 category와 맞지 않은 mode를 사용한다면 예상치 못한 동작이 발생할 수 있다.
대표적인 예로는
videoRecording은 record와 playAndRecord 카테고리에서만 사용할 수 있고
voicePrompt는 playAndRecord 카테고리와 함께 사용할 수 없다.
Mode | 역할 | 특징 |
default | 기본모드 | 별도의 요구 사항 없이 일반적인 오디오 재생 / 녹음 시 사용 |
voiceChat | 음성 채팅 모드 | 오디오 품질을 음성 통신에 최적화하여 에코 제거 및 노이즈를 억제 |
videoChat | 영상 통화 모드 | voiceChat과 비슷하지만 영상과 함께 사용된다. |
gameChat | 게임 음성 채팅 모드 | 게임 내 배경음과 함께 음성 채팅을 함께 처리 |
videoRecording | 비디오 녹화 모드 | 비디오와 오디오가 동시에 기록되는 처리 |
measurement | 오디오 측청 모드 | 입력 및 출력에서 불필요한 처리(에코 제거 노이즈 억제) 를 제거하여 정확한 오디어 데이터를 제공 |
moviePlayback | 영화 및 비디오 재생 모드 | 오디오 품짐을 향상시켜 영화 시청 시 높은 음향 품질을 제공 |
spokenAudio | 팟캐스트 모드 | 음성 중심의 콘텐츠에 최적화된 모드 |
broadcast | 스트리밍 방송 모드 | 실시간 스트리밍과 같은 방송에 최적화된 모드 |
voicePrompt | 음성알림 모드 | 다른 오디오를 중단하지 않고 음성을 알리는 모드 대표적으로 네비게이션 앱이 해당된다. |
c. 카테고리 옵션
다른 앱들이랑 우리 오디오랑 어떻게 호환할지
CategoryOptions | 역할 | 특징 |
mixWithOthers | 다른 앱과 함께 | 다른 앱에서 재생중인 오디오를 중단하지 않고 함께 사용 |
duckOthers | 다른 앱의 볼륨 줄임 | 앱의 오디오 재생 시 다른 앱의 오디오를 일시적으로 줄임 |
allowBluetooth | Bluetooth 허용 | 카테고리가 playAndRecord일 때, Bluetooth 장치를 오디오 입력 또는 출력 장치로 사용할 수 있다. |
allowBluetoothA2DP | A2DP 프로파일 지원 | A2DP(Advanced Audio Distribution Profile)는 고음질 오디오 전송을 위한 Bluetooth 프로토콜 이 옵션은 주로 고음질 오디오 출력이 필요한 상황에서 사용 대표적으로 음악 스트리밍에서 고음질 오디오 재생 시 |
allowAirPlay | AirPlay를 통해 오디오 재생 |
AirPlay를 사용하여 오디오를 외부 장치 Apple Tv, AirPlay 지원 스피커로 전송 |
defaultToSpeaker | 기기 스피커 이용 | 일반적으로 기기의 스피커만 사용 대표적으로 스피커몬 모드 때 사용 |
interruptSpokenAudioAndMixWithOthers | 다른 오디오 중단 또는 함께 |
다른 앱의 오디오를 중단하거나 섞어서 재생되도록함 |
overrideMutedMicrophoneInterruption | 마이크 음소거 시 녹화 | 마이크가 음소거 시 녹음이 차단되지만 이 옵션은 음소거가 되어 있어도 녹음을 허용 |
Audio Route란?
오디오가 어디서 입력되었고 어디로 출려되는 지 전체적인 경로를 의미한다.
1. 오디오 입력 경로 (Audio Input Route)
- 오디오 입력에 대한 경로를 결정
- 기기 마이크, Bluetotth 장치등이 있다.
2. 오디오 출력 경로 (Audio Output Route)
- 오디오 출력에 대한 경로를 결정
- 스피커, 아이폰, 블루투스 기기등이 있다.
- builtInSpeaker: 기기 내장 스피커.
- headphones: 유선 이어폰.
- bluetoothA2DP: A2DP Bluetooth 장치(고음질 오디오 지원 Bluetooth 장치).
- bluetoothLE: 저전력 Bluetooth 장치.
- airPlay: AirPlay 장치를 통한 오디오 출력.
3. 오디오 경로 변경 감지
AVAudioSessionRouteChangeReasonKey
- newDeviceAvailable - 새로운 기기 연결 시. 현재의 새로운 Audio output 이 어디로 route 되었는지의 정보가 들어있음
- oldDeviceUnavailable - 기존의 기기 연결 해제 시. 해제된 route에 대한 정보가 들어있음
자세한 것은 routeChangeNotification 을 참고하자
@objc private func handleRouteChanged(notification: Notification) {
guard
let info = notification.userInfo,
let reason = info[AVAudioSessionRouteChangeReasonKey] as? AVAudioSession.RouteChangeReason
else { return }
if reason == .oldDeviceUnavailable {
let lastRoute = info[AVAudioSessionRouteChangePreviousRouteKey] as! AVAudioSessionRouteDescription
let lastOutput = lastRoute.outputs[0]
let port = lastOutput.portType
if port == .headphones {
// 재생 중지
}
}
}
Audio Interrupt란?
우리 앱에서 OS 오디오 세션을 Active하고 오디오를 재생하는 도중, 우리 앱의 오디오보다 우선순위가
더 높은 오디오 이벤트가 발생할 수 있다.
예를 들면, 폰에서의 incoming call이 있다. 이 경우 call 의 우선순위가 더 높기 때문에 앱에서 재생되던
오디오는 멈추고 전화벨 소리가 재생된다.
우리 앱의 입장에서 이것이 ‘Audio Interrupt가 발생한 것'이다.
Interuppt Begin
- 우리 앱이 오디오를 재생하는 도중, 우선순위가 더 높은 오디오 이벤트가 발생했을 때
- 우리 앱은 경쟁에서 밀려 비활성화됨
- 오디오 세션으로부터 Audio Interrupt Notification을 받을 수 있음
- 재생 중이던 오디오가 멈췄기 때문에 UI적으로도 핸들링 필요, ex) 재생버튼을 일시 재생버튼으로 변경 등
Interuppt end
- 우리 앱에 Interrupt를 발생시킨 외부 요인의 세션이 끝났을 때
- 항상 호출된다는 보장은 없다.
- 마찬가지로 오디오 세션으로부터 Audio Interrupt Notification을 받을 수 있음
- 앱에서 오디오 세션을 다시 활상하 하고 일시정지됐던 오디오를 resum하는 등 핸들링이 필요
참고
OS로부터 인터럽트 신호는 받을 수 있으나, 그 원인이 어떤 것인지는 알 수 없다.
따라서 실제 코드에서는 Call Begin/ End를 감지할 수 있는 CallKit을 함께 사용하여 구현하고 있다.
인터럽트 원인이 Call인지, 외부앱인지에 따라 다른 처리가 필요하기 때문이다.
또한 실제 프로젝트에서는, 외부앱에 의해 Interrupt 되어 오디오 세션이 Deactive 된다고 해서 외부앱의 재생이 끝나는 것만
기다리고 있으면 안되는 경우가 있다.
Deactivate 된다고 해서 외부앱의 재생이 끝나는 것만 기다리고 있으면 안되는 경우가 있다.
Deactivate 된 것을 감지한 직후라도, Sound 재생이 반드시 필요한 경우에는 Audio Session을 다시 Activate
해야 한다는 것을 주의하자.
참고
'iOS > Framework' 카테고리의 다른 글
[ 부스트 캠프 ] Shook 서비스 플레이어 만들기 (0) | 2024.12.01 |
---|---|
AVFoundation (3) [AVPlayerLayer] (1) | 2024.10.22 |
AVFoundation (2) [AVPlayer, AVPlayerItem] (0) | 2024.10.21 |
AVKit (4) | 2024.10.21 |
AVFoundation (1) [AVAsset] (1) | 2024.10.21 |