안드로이드 프레임워크에서 소리와 영상을 재생하기 위해 사용되는 클래스는 아래와 같습니다.
# MediaPlayer
- 오디오 및 비디오 파일과 스트림 재생을 위해 쓰입니다.
- 소리와 영상을 재생하기 위한 기본 API입니다.
# AudioManager
기기의 오디오 소스와 오디오 출력을 관리하는 클래스입니다.
# Audio Focus
2개 이상의 앱이 audio를 하나의 stream으로 동시에 재생할 수 있다.
시스템들은 이것을 믹스한다. 이는 유저에게 소음이 될 수 있다.
이를 예방하기 위해 Audio Focus라는 개념을 도입.
하나의 앱만 audio focus를 가질 수 있다.
앱이 audio output을 하려면, audio focus를 요청해야 한다.
focus를 획득하면 소리를 재생할 수 있다.
획득 후에 재생을 끝마칠 때까지 focus를 유지하지 못할 수 있다.
다른 앱이 focus를 요청하여 취득하는 경우
Android 12 전에는 audio focus는 시스템에 의해 관리되지 않았다. (앱이 audio focus 가이드 라인을 준수하도록 권장하였다.)
Android 11 이하에서 앱이 audio focus를 잃은 후에도 계속 무언가를 크게 재생한다면, 시스템이 이를 막지 않았다.
올바르게 작동하는 오디오 앱은 다음 일반적인 가이드 라인을 준수해야 한다.
1. 재생 전에 requestAudioFocus()를 가급적 빨리 호출하고, AUDIOFOCUS_REQUEST_GRANTED를 획득한다.
Media Session의 onPlay() callback에서 호출하는 것이 좋다.
2. 다른 앱이 audio focus를 얻으면 (내가 audio focus를 잃으면) 재생을 중단(stop 하거나 포즈시키거나, 볼륨을 줄인다.)
3. 재생이 끝나면 audio focus를 놓아준다.
유저가 재생을 "pause"시킨거라면 꼭 focus를 놓아줄 필요는 없다.
4. AudioAttribute는 앱이 재생하는 오디오 타입을 명시한다.
예를 들어 음성을 재생한다면 CONTENT_TYPE_SPEECH를 명시해 준다.
Android 12 or later
Audio focus가 system에 의해 관리된다.
다른 앱에서 audio focus를 얻어가면 시스템에서 focus를 잃은 재생을 fade out시킨다.
그리고 수신통화가 있을 때 오디오 재생을 묵음시킨다.
audio focus를 사용하는 미디어나 게임 앱은 audio focus를 잃은 후에 오디오를 재생해서는 안 된다.
Android 12이상에서는 이를 system이 강제한다.
다른앱이 focus를 가지고 재생을 하고 있는데, 내 앱이 focus를 요청하면 system이 다른 앱의 재생을 fade out시킨다.
fade out동작은 다음 조건이 만족되면 발생.
- 현재 재생중인 앱이 다음 조건 모두를 만족한다.
- AudioAttributes.USAGE_MEDIA, AudioAttributes.USAGE_GAME attribute를 가짐.
- audio focus를 AUDIOFOCUS_GAIN으로 요청 했음.
- 재생하는 content type이 AudioAttributes.CONTENT_TYPE_SPEECH가 아님.
- 새로 focus를 요청하는 앱이 AUDIOFOCUS_GAIN으로 focus를 요청함.
위 조건이 만족하면 system이 현재 재생중인 앱의 audio를 fade out시키고, fade out이 끝나면 그 앱에 focus loss를 알려준다.
그 앱은 다시 audio focus를 요청할 때까지 묵음 상태로 남아 있는다.
Android 8.0 ~ Android 11
Audio focus가 system에 의해 관리되지 않는다.
requestAudioFocus() 함수를 호출할 때 반드시 AudioFocusRequest를 함께 전달해야 한다.
AudioFocusRequest에는 audio context, capability등의 정보가 들어간다.
System은 이 정보를 바탕으로 audio focus의 획득과 상실을 자동으로(?) 관리한다.
Audio focus를 놓아주기 위해서는 동일하게 AudioFocusRequest를 인자로 받는 abandonAudioFocusRequest()를 호출해주어야 한다.
이들에 전달되는 AudioFocusRequest 객체는 동일한 것이어야 한다.
Audio Focus Request를 생성하기 위해서는 AudioFocusRequest.Builder를 사용한다.
Focus요청은 반드시 항상 요청 type을 명시해야 하므로, 이는 생성자에 전달되어야 한다.
FocusGain field는 꼭 지정 되어야 하고, 나머지는 optional하다.
- setFocusGain() : 8.0이전의 durationHint에 적용되던 값과 동일한 값을 설정해주는 필수 설정값이다.
- setAudioAttributes() : AudioAttributes는 use case를 기입한다.
시스템이 이 정보를 보고 audio focus의 획득과 상실을 관리한다.
Attributes는 stream type의 명시를 대체한다.
8.0이상에서 볼륨 컨트롤 이외의 stream type은 deprecate되었다. audio player에서 사용하는 focus request와 동일한 attributes를 사용해야 한다.
기본값은 AudioAttributes.USAGE_MEDIA이다. - setWillPauseWhenDucked() : 다른 앱이 AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK에 대한 focus를 요청하면, 이 앱은 onAudioFocusChange callback을 받지 않는다.
왜냐하면 시스템이 알아서 duck을 할 수 있기 때문이다.
볼륨을 줄이는 대신 재생을 멈추고 싶다면, setWillPauseWhenDucked(true)를 호출해주며, OnAudioFocusChangeListener를 달아주어야 한다. - setAcceptDelayedFocusGain() : 다른 앱이 focus를 잠궈놓으면 audio focus 요청이 실패할 수 있다.
이 함수는 지연된 focus gain을 가능하게 한다.
비동기적으로 focus획득이 가능할 때 얻는다는 이야기이다.
delayed focus gain은 AudioManager.OnAudioFocusChangeListener를 주었을 때만 작동한다. - setOnAudioFocusChangeListener() :willPauseWhenDucked(true) 또는 setAcceptDelayedFocusGain(true)를 주었을 때만 유효하다.
Android 7.1 이하
Audio focus는 system에 의해 관리되지 않는다.
requestAudioFocus()와 abandonAudioFocus()를 사용하여 audio focus를 관리한다.
AudioManager.OnAudioFocusChangeListener를 등록해서 callback을 받는다.
requestAudioFocus()를 호출할 때 duration hint를 반드시 지정해서 다른 앱이 이 조건을 존중할 수 있도록 해야한다.
- 영구적인 audio focus를 위해서는 AUDIOFOCUS_GAIN을 요청해야 한다.
- 일시적인 audio focus를 위해서는 AUDIOFOCUS_GAIN_TRANSIENT를 요청해야 한다.
- ducking을 하는 일시적인 audio focus를 위해서는 AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK을 요청한다.
이 경우 기존 focus를 가지고 있는 친구는 볼륨이 낮아지면서 내용물은 mix가 된다. - ducking은 audio stream을 간헐적으로 사용하는 네비게이션 등의 앱에 대해 유용하다.
requestAudioFocus() 함수는 AudioManager.OnAudioFocusChangeListener를 요구한다.
이 녀석은 media session을 소유하는 activity 또는 service에서 생성되어야만 한다.
AUDIO FOCUS 값
https://developer.android.com/reference/android/media/AudioManager?hl=ko#AUDIOFOCUS_GAIN
참조 :
https://shinjekim.github.io/android/2019/10/11/Android-MediaPlayer-%EA%B0%9C%EC%9A%94/
https://aroundck.tistory.com/7993
https://blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=bootpay&logNo=221156088050
'안드로이드' 카테고리의 다른 글
아키텍처는 왜 중요한가? (MVC, MVP, MVVM, Clean Architecture, ViewModel, 모듈) 알아 보자! (0) | 2024.03.26 |
---|---|
[Android] 루팅이란? 루팅 체크 방법 (0) | 2024.03.22 |
[Android] DiffUtil에 대해 알아보자 (0) | 2024.03.20 |
[Android] MediaStore에서 미디어 파일 정보 읽는 방법 (0) | 2024.03.20 |
Android Q 파일 삭제 ScopeStorage 삽질 (2) | 2024.03.20 |