티스토리 뷰
Intro
안드로이드에서 음악, 영상 등을 재생하려면 MediaPlayer를 사용해야 한다.
오늘 해볼 음원 재생은 따로 뷰는 필요없지만, 그만큼 리소스 관리를 잘하여야 한다.
음원을 재생 후 따로 리소스 해제를 제대로 해주지 않는다면, 에러가 발생하거나 기능 자체가 원하는 의도대로 제대로 동작하지 않을 것이다.
내가 이번에 했던것은 단순하게 raw 폴더의 리소스를 재생하는 것이었지만, 2개의 리소스를 겹치지 않게 연달아 실행하기 위해 몇가지 셋팅이 필요했다.
Summary
MediaPlayer는 기본적으로 제공되는 라이브러리이고, developers에서는 다음과 같이 설명하고 있다.
미디어 프레임워크의 가장 중요한 구성요소 중 하나는 MediaPlayer 클래스입니다. 이 클래스의 객체는 최소한의 설정으로 오디오와 동영상을 모두 가져오고 디코딩하며 재생할 수 있습니다. 다음과 같은 여러 미디어 소스를 지원합니다.
- 로컬 리소스
- 콘텐츠 리졸버에서 가져올 수 있는 것과 같은 내부 URI
- 외부 URL(스트리밍)
Dependency
만약 네트워크 기반 미디어를 스트리밍하는 경우, Manifest에 아래 권한을 추가한다.
<uses-permission android:name="android.permission.INTERNET" />
안드로이드에서 기본적으로 제공함으로 따로 Dependency를 추가할 필요가 없다.
Using
사용 방법은 정말 간단하다.
만약 raw 리소스 폴더에 해당 미디어 파일이 있다면, 아래와 같이 쉽게 재생이 가능하다.
var mediaPlayer: MediaPlayer? = MediaPlayer.create(context, R.raw.sound_file_1)
mediaPlayer?.start()
스트리밍 타입을 설정하고 좀 더 안전하게 호출하고 싶다면, DataSource를 설정해 준다.
그리고 prepare함수를 사용해 버퍼링 후 재생한다.
val mediaPlayer: MediaPlayer? = MediaPlayer().apply {
setAudioStreamType(AudioManager.STREAM_MUSIC)
setDataSource(url)
prepare()
start()
}
현재는 setAudioStreamType이 Deprecated되어 Attribute를 설정하라고 한다.
아래와 같이 해주자.
val attr = AudioAttributes.Builder().apply {
setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
}.build()
MediaPlayer().apply {
setDataSource(/* 파일 */)
setAudioAttributes(attr)
prepare()
start()
}
자 이제 파일은 어떻게 가져와서 재생할까?
네트워크 기반으로 한다면, URL을 입력해주면 되는 부분이지만, 내가 해야할 것은 파일을 불러와서, 2개의 음원을 연달아 재생해야 한다.
이땐 AssetFileDescriptor를 사용하면 된다.
private fun soundAlarmEffect(context: Context?): AssetFileDescriptor? =
context?.resources?.openRawResourceFd(R.raw.alarm_effect)
context를 받아와서 리소스에 접근한 뒤 raw 리소스를 불러온다.
val attr = AudioAttributes.Builder().apply {
setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
}.build()
MediaPlayer().apply {
setDataSource(soundAlarmEffect(context))
setAudioAttributes(attr)
prepare()
start()
}
일단 이렇게 하여 실행해 보니 정상적으로 재생된다.
2개를 연달아 재생하기 위해, 파일을 하나 더 가져온다.
private fun soundYes(context: Context?): AssetFileDescriptor? =
context?.resources?.openRawResourceFd(R.raw.sound_yes)
그리고 재생 함수도 조금 바꿔주자..
내가 선택한 방법은 리소스 타입을 지정해 놓고, 파일을 불러와 순차적으로 실행해 주었다.
fun soundStart(type: Int, context: Context?): MediaPlayer {
val descriptor = soundType(type, context)
val attr = AudioAttributes.Builder().apply {
setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
}.build()
val mediaPlayer = MediaPlayer()
descriptor?.let {
try {
mediaPlayer.apply {
setDataSource(it.fileDescriptor, it.startOffset, it.length)
setAudioAttributes(attr)
prepare()
start()
}
} catch (e: IOException) {
soundStop(mediaPlayer)
Log.e("SoundPlay","IOException - ${e.message}")
} finally {
try {
it.close()
} catch (e: IOException) {
Log.e("SoundPlay","IOException - ${e.message}")
}
}
}
return mediaPlayer
}
파일을 가져오고 재생하는 과정에서 발생할 수 있는 예외처리를 해준다.
그리고 사용한 리소스 파일도 close하여 리소스 사용을 초기화한다.
만약 파일을 잘못된 경로로 가져온 경우를 방지하기 위해 catch 구문에서 아래 함수를 실행한다.
fun soundStop(mediaPlayer: MediaPlayer?) {
mediaPlayer?.stop()
mediaPlayer?.release()
}
자 이제 준비는 끝났고, 실행만 해주면 된다.
fun soundYesPlay(context: Context?) {
soundStart(SOUND_ALARM_EFFECT, context).setOnCompletionListener { mp1 ->
mp1.release()
soundStart(SOUND_YES, context).setOnCompletionListener { mp2 ->
mp2.release()
}
}
}
위와 같이 함수를 만들어, ALARM_EFFECT를 먼저 실행하고 리스너를 통해 해당 MediaPlayer를 릴리즈 한다.
곧바로 두 번째 리소스를 실행하고, 실행이 완료되면 역시 릴리즈 해준다.
버튼 리스너에 해당 함수를 포함하여 실행해 보니 문제없이 잘 된다.
* 전체 소스
https://github.com/rlwhd0716/tistory_library/tree/main/Android/MediaProject
'Android > Kotlin' 카테고리의 다른 글
[Kotlin] View에 로테이트 애니메이션(Rotate Animation) 적용하기 (0) | 2023.05.31 |
---|---|
[Android] StartActivity 애니메이션 없이 실행하기 (0) | 2023.05.30 |
[Kotlin] AlertDialog 사용하기 (0) | 2023.04.22 |
[Kotlin] 앱 실행 상태 체크하기(백그라운드 상태 체크) (0) | 2023.03.30 |
[Kotlin] ViewPager2 사용법 (0) | 2020.08.18 |
- Total
- Today
- Yesterday
- 음성재생
- sqld 자격증 합격
- 아이폰앱개발
- dart
- 코틀린
- 아이폰
- 격파르타 후기
- ~=
- 변수
- 격파르타 합격후기
- 함수
- IOS
- gem update
- rotate
- Java
- FLUTTER
- 격파르타 장점
- .toml
- 버전카타로그
- toml
- Swift
- 연산자
- 자바
- Android
- rotation
- Xcode
- Kotlin
- 안드로이드
- 스위프트
- NoAnimation
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |