출처: https://jamssoft.tistory.com/31 [뭘해야하는가?]
안드로이드의 Mediaplayer나 Ringtone을 사용할 경우, 소리의 종류를 구분해 주어야 한다. 이 종류에 따라서 차이가 나타나게 되는 데, 필자가 확인바로는 한개는 볼륨조절이고, 또 하나는 출력방향이다. 예를들어 이 종류를 음악으로 한 경우, 볼륨조절을 할 때, 음악의 볼륨을 바꿔 줘야 변경이 되지, 알림(Notification)볼륨을 바꿔 봤자 소용이 없다. 또한 중요한 것이 알람[Alarm]으로 설정하면, 기기에 이어폰이 꼽혀있다고 해도, 외부스피커로만 소리가 나온다. 필자의 경우 이어폰을 꼽혀있을 경우, 소리가 이어폰으로 나올 줄 알았는 데, 전혀 그렇지가 않았다. 이 사실을 정확히 몰라 출시된 앱마저도 정확한 처리가 되어있지 않다.
소리의 종류를 구분을 해주는 함수는 MediaPlayer도 Ringtone도 setAudioStreamType으로 이름이 같다. 하지만, 이 함수는 API 26[Oreo]에서 Deprecate되어 호환성있는 코드로 작성이 되어야 한다.(필자가 미리 살펴본 바로는 변경된 setAudioAttributes는 좀 더 세분화가 되어 있긴 하지만, 그리 의미있는 변경으로 보이지는 않는다.) 어쩔 수 없이 구글이 하라면 안 할수 없으니, 좀 더 살펴보도록 하자.
setAudioStreamType함수는 파라미터가 AudioManager.STREAM_* 식으로 정의[definition]되어 있으며, setAudioAttributes함수는 AudioAttributes.USAGE_* 식으로 되어 있다. 놓치지 말고 잘 봐야 할 것이 AudioManager와 AudioAttributes로 정의되어 있는 class가 아예 다르다. 섞어서 쓰는 실수가 없도록 해야 한다.
setAudioStreamType함수는 API 26[Oreo]에서 deprecate되었지만, setAudioAttributes함수는 API 21[Lollipop]에서 추가 되었다. Deprecate시점과 추가된 시점에 Overlap이 있다. 따라서, 구분하는 코드는 [26미만]을 사용하지 말고 [21이상]으로 처리하는 것이 좋을 듯하다. 뭐 도긴개긴일 것 같긴 하다.
setAudioStreamType
AudioManager에 선언된 종류는 다음과 같다.
STREAM_ACCESSIBILITY | 접근성(스크린리더 같은 것) |
STREAM_ALARM | 알람[Alarm]소리(ex:일어나요에 알람) |
STREAM_DTMF | 전화기다이얼 버튼 누를 때 나는 전자음소리 |
STREAM_MUSIC | 음악소리 |
STREAM_NOTIFICATION | 알림[Notification]소리(ex:새동영상이 올라왔음 소리) |
STREAM_RING | 전화왔을 때 울리는 소리 |
STREAM_SYSTEM | 시스템사운드[이게 뭘까?] |
STREAM_VOICE_CALL | 통화소리[상대방이 말하는 소리] |
USE_DEFAULT_STREAM_TYPE | 기본? |
알람[Alarm]과 알림[Notification]을 잘 구분해서 확인하기 바란다.
setAudioAttributes
21부터 사용되는 AudioAttributes.USAGE_*은 다음과 같다. 좀 많다.
USAGE_ALARM | 알람[Alarm]소리(ex:일어나요에 알람) |
USAGE_ASSISTANCE_ACCESSIBILITY | 접근성 |
USAGE_ASSISTANCE_NAVIGATION_GUIDANCE | 차 네비게이션소리 |
USAGE_ASSISTANCE_SONIFICATION | 사용자 인터페이스 소리(터치음 같은 것) |
USAGE_ASSISTANT | 이건.. Google Assistant나 시리, 빅스비 같은 것 |
USAGE_GAME | 게임오디오(이게 뭐소리나.. 게임에서 나는 소리가 한두개도 아니고.) |
USAGE_MEDIA | 음악, 사운드트랙, 비디오 같은 것 |
USAGE_NOTIFICATION | 알림[Notification]소리(ex:새동영상이 올라왔음 소리) |
USAGE_NOTIFICATION_COMMUNICATION_DELAYED | 즉시처리불가 소리?(이메일같이 바로처리되지 않는 소리) |
USAGE_NOTIFICATION_COMMUNICATION_INSTANT | SMS나 챗팅 뭐.. 카톡소리 같은 것.. |
USAGE_NOTIFICATION_COMMUNICATION_REQUEST | 이 건 번역하기 귀찮아서( 상황은 알겠는데...) 그냥 영어원문으로 "Usage value to use when the usage is a request to enter/end a communication, such as a VoIP communication or video-conference." |
USAGE_NOTIFICATION_EVENT | 사용자가 뭘 좀 해야하는 알림 밧데리가 떨어져 간다라던가, 리마인더 같은 것 |
USAGE_NOTIFICATION_RINGTONE | 전화왔을 때 울리는 소리 |
USAGE_UNKNOWN | 뭔지 모를 때(이럴 거면 세분화 왜 했는 지, ETC라고 하던지..) |
USAGE_VOICE_COMMUNICATION | 전화통화소리(아마 상대방 소리) |
USAGE_VOICE_COMMUNICATION_SIGNALLING | 이 것도 그냥 원문으로 Usage value to use when the usage is in-call signalling, such as with a "busy" beep, or DTMF tones. |
(필자가 볼 때 세분화의 분류가 이상해 보인다.)
AudioAttributes는 단순히 이 것으로 끝나지 않고 또 다른 분류가 있다. 이 분류는 다음과 같다. 이게 좀 무슨 생각으로 다른 분류를 만들었는 지 모르겠지만, 필자가 볼 때, USAGE_와 구분되는 상황이 있을 것 같긴 하다.
AudioAttributes.CONTENT_TYPE_*
CONTENT_TYPE_MOVIE | 사운드트랙, 영화나 TV 프로그램 |
CONTENT_TYPE_MUSIC | 음악 |
CONTENT_TYPE_SONIFICATION | 사용자 인터페이스 소리 ( 게임에서 보너스소리도 이 곳에 넣는 거란다. 앞뒤가 안맞군 ) |
CONTENT_TYPE_SPEECH | 스피치용 |
CONTENT_TYPE_UNKNOWN | 모를 때(제발 모른다[알려지지않음]가 아니고 분류없음이라고 해야지..) |
(아무리봐도 좀 깊이 생각해서 만든 것 같진 않다. 아마 필요가 생겨 급하게 만든 것 같다.)
출력의 방향
이어폰인지 스피커인지 스피커라면 수화용스피커인지 소리 큰 스피커인지 종류에 따라 구분이 된다. 필자가 이 글을 작성한 이유이기도 하다. 필자가 MediaPlayer.setAudioStreamType() 함수를 사용하여, 간단히 하나의 기기[LG G2]에서 테스트를 한 것이라 정확하다고 할 수 없다. 플레이 파일은 기본 Ringtone이다.(LG G2의 라이프 이스 굿.. [많이 시끄럽다.])
여기서
내부스피커 : 기기로 통화 할 때 나오는 수화용 스피커
외부스피커 : 기기에 달려있는 스피커(음악틀면 나오는 것/소리 큰 것)
STREAM_ACCESSIBILITY | 이어폰 꼽으면 이어폰 / 빼면 외부스피커(볼륨조절이 안된다.) |
STREAM_ALARM | 이어폰을 꽂아도 외부스피커로 난다(볼륨조절이 안된다.) |
STREAM_DTMF | 이어폰 꼽으면 이어폰 / 빼면 외부스피커 |
STREAM_MUSIC | 이어폰 꼽으면 이어폰 / 빼면 외부스피커 |
STREAM_NOTIFICATION | 아예 플레이가 안되네~(왜지?) |
STREAM_RING | 아예 플레이가 안되네~(왜지?) |
STREAM_SYSTEM | 아예 플레이가 안되네~(왜지?) |
STREAM_VOICE_CALL | 이어폰 꼽으면 이어폰 / 빼면 *내부스피커* |
USE_DEFAULT_STREAM_TYPE | 아예 플레이가 안되네~(왜지?) 이건 원래 없는 건가? |
위에 테스트에서 [아예 플레이가 안되는 것]은 굳이 이유를 찾고 싶지 않아 테스트를 그냥 멈췄다. 필자는 STREAM_MUSIC과 STREAM_ALARM만 처리하면 되는 상황이었다. [Voice call]의 경우 내부스피커인게 좀 신기하다. 당연한 것이겠지만.. 가끔 써먹을 수 있을 듯 하다. 볼륨조절이 안 되는 것은 원인을 모르겠다. 굳이 막을 필요는 없어 보이는데 말이다.
구분예제
실제 구분하는 예제 코드는 다음과 같다.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
AudioAttributes aa = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_ALARM)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build();
ringtone.setAudioAttributes(aa);
} else {
ringtone.setStreamType(AudioManager.STREAM_ALARM);
}
버전을 구분했고, 롤리팝이상일 경우 다행히도 빌더를 제공해 주기에 쉽게 처리가 가능하다. API Reference에서도 늘 적혀 있 듯, 이 코드에서 사용된 setAudioAttributes와 setStreamType은 MediaPlayer의 prepare()이전에 넣어줘야 한다.
끝~
(구글은 문서에 예제 좀 넣어 줘야지.. 이리저리 뒤지고 다니게 좀 만들지 말았으면 좋겠다. API Reference만 만들면 안된다.. 좀.. 구글아~ 읽고 계세요~? )
'개발 > 안드로이드' 카테고리의 다른 글
Android ConstraintLayout 분석 - 2 (0) | 2019.06.13 |
---|---|
Android ConstraintLayout 분석 - 1 (0) | 2019.06.13 |
[Android] FileProvider :: android.os.FileUriExposedException (0) | 2019.06.11 |
Uri.fromFile() 사용 시, FileUriExposedException 발생하는 경우 (0) | 2019.06.11 |
RxJava와 Room DB (0) | 2019.05.31 |
댓글