[Android] SoundPool

gang_shik·2021년 8월 30일
0

SoundPool?

  • 안드로이드에서 사운드 재생 방법은 2가지 있음

  • SoundPool과 MediaPlayer, 여기서 SoundPool은 알림사운드, 게임효과등 짧은 사운드 클립에 적합하고 MediaPlayer는 노래와 같은 더 큰 사운드파일을 재생할 때 적합함

  • 그래서 SoundPool을 통해 특정 행동에 따른 효과음 배경음을 사용할 수 있고 타이밍에 맞춰 정확히 그 시점에 준비된 소리가 나게끔 할 수 있음

  • 이러면 여러개의 음원을 미리 로딩해 놓고, 필요한 시간에 각각을 혹은 동시에 재생시킬 수 있는 장점이 있음

  • SoundPool 재생을 위해 먼저 사운드 파일을 넣어둬야함, 이를 res 폴더 밑에 raw 폴더를 생성하여 해당 디렉토리에 사운드 파일을 넣어둠

  • 그래서 이렇게 파일에 넣어둔걸 바탕으로 해당 파일을 load를 통해 불러오고 효과음을 재생하고 중지하는 등의 코드를 직접 넣어서 적용할 수 있음


예시

  • 사운드 파일을 실행전 로드를 위해서 초기화를 함
// 사운드 파일 실행전 로드하기 위한 메소드
    private fun initSounds() {
        // SoundPool을 통해서 로드할 것임, 로드된 SoundId를 저장함
        tickingSoundId = soundPool.load(this, R.raw.timer_ticking, 1)
        bellSoundId = soundPool.load(this, R.raw.timer_bell, 1)
    }
  • 그리고 로드한 파일에 대해서 예시에는 타이머가 시작할 때 ticking을 실행하고 타이머가 끝날때 bell을 실행하게끔 메소드 안에 삽입시켜 play를 걸어둠
// SeekBar를 뗐을 때 CountDown을 시작하는데 이 로직이 너무 SeekBar에 많이 몰려서 추상화함
    private fun startCountDown() {
        // 다시 시작하는 경우를 생각해서 변수로 선언한 곳에 할당하고 시작함
        currentCountDownTimer = createCountDownTimer(seekBar.progress * 60 * 1000L)// Milliseconds로 만들어서 넘겨줘야함
        currentCountDownTimer?.start()
        // 카운트다운 시작과 동시에 Soundpool도 실행시킴, let을 통해 null이 아닐 경우에만 호출하게 함
        tickingSoundId?.let { soundId ->
            soundPool.play(soundId, 1F, 1F, 0, -1, 1F) // 사운드 실행 조건을 검
        }
    }

// onFinish에 너무 많은 로직이 있어서 한 번에 추상화시킴
    private fun completeCountDown() {
        // 볼 것도 없이 끝난것이므로 다 0으로 설정해줌
        updateRemainTime(0)
        updateSeekBar(0)
        // 모두 다 종료됐을 때 bell 소리가 나게함, 여기서 ticking 소리를 일시정지시키고 실행시켜야함
        soundPool.autoPause()
        bellSoundId?.let { soundId ->
            soundPool.play(soundId, 1F, 1F, 0, 0, 1F)
        }
    }
  • 하지만 이렇게 단순하게 실행과 종료를 할 수 있는 앱이면 상관이 없지만 만약 위처럼 타이머는 계속 가고 있기 때문에 그리고 앱이 백그라운드로 넘어가도 소리가 계속 날 수 있기 때문에 이를 안드로이드 수명주기에 맞춰서 일시정지를 추가해줘야함, 그냥 멈췄을 때도 마찬가지이고
// 카운트다운을 아예 종료하는 로직, 소리 역시 아예 종료시킴
    private fun stopCountDown() {
        currentCountDownTimer?.cancel()
        currentCountDownTimer = null
        soundPool.autoPause()
    }
    
    override fun onResume() {
        super.onResume()
        // 다시 실행시 다시 사운드 시작시킴, 백그라운드 진입하고 다시 실행시키면 소리가 다시 남
        soundPool.autoResume()
    }

    override fun onPause() {
        super.onPause()
        // 앱이 화면에서 보이지 않으면 사운드를 일시정지시킴
        soundPool.autoPause()
    }

    // 사운드 파일은 그 용량이 많이 나감, 그러므로 이를 안 쓸 경우 메모리에서 해제해주는 것이 중요함
    override fun onDestroy() {
        super.onDestroy()
        // 더 이상 앱을 사용하지 않을 때를 가정해서 사운드를 해제함
        soundPool.release()
    }
profile
Stay Humble, Hustle Hard

0개의 댓글