Tistory View

안드로이드의 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만 만들면 안된다.. 좀.. 구글아~ 읽고 계세요~? )

 

Replies
Reply Write