본문 바로가기

Android

[Android] AudioTrack 재생

728x90

Android 앱에서 음원 및 Raw Data 재생 시 AudioTrack 과 MediaPlayer 를 이용해서 재생할 수 있다. AudioTrack 과 MediaPlayer 는 각 용도에 맞게 선택하여 사용한다.

MediaPlayer

  • 음악과 같이 백그라운드 재생을 할 경우
  • STATIC 한 시간이 아닌 음원을 재생할 경우

AudioTrack

  • AudioChannel Config 설정을 원할 경우
  • PCM Raw Data Buffer 를 바로 재생할 경우

MediaPlayer

  1. Raw 파일의 Wav 음원을 재생하는 경우
    • AudioAttribute 설정(안드로이드 O이상 지원)이 필요없을 때에는 MediaPlayer 를 바로 Create 하고 음원을 재생한다.
val mediaPlayer = MediaPlayer.create(context, resId)
mediaPlayer.start()
    • AudioAttribute 설정이 필요한 경우 RAW 폴더의 res 음원 파일을 uri 로 변환하여 재생한다.
val mediaPlayer = MediaPlayer()
val ttsUri = Uri.parse("android.resource://" + context.packageName + "/" + resId)

mediaPlayer.let { player ->
  player.setOnPreparedListener {
    Timber.tag(logTag).d("playMediaPlayer - prepare complete")
    player.start()
  }

  player.setOnCompletionListener {
    Timber.tag(logTag).d("playMediaPlayer - complete, currentType=$currentType")
    // 재생 완료 후 동작 처리...
  }

  player.reset()
  player.setDataSource(context, uri)
  /**
  * 각 음원 Stream 에 맞는 타입을 설정한다.
  */
  player.setAudioAttributes(AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ASSISTANT).setContentType(AudioAttributes.CONTENT_TYPE_SPEECH).build())
  player.prepareAsync()
}

2. data 영역에 임시로 저장한 wav 파일을 재생하는 경우

val fis = context.openFileInput(FILE_NAME)
val mediaPlayer = MediaPlayer()

mediaPlayer.let { player ->
  player.setOnPreparedListener {
    Timber.tag(logTag).d("playMediaPlayer - prepare complete")
    player.start()
  }

  player.setOnCompletionListener {
    Timber.tag(logTag).d("playMediaPlayer - complete")
    // 재생 완료 후 동작 처리...    
  }

  player.reset()
  player.setDataSource(fis.fd)
  /**
  * 각 음원 Stream 에 맞는 타입을 설정한다.
  */
  player.setAudioAttributes(AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_ASSISTANT).setContentType(AudioAttributes.CONTENT_TYPE_SPEECH).build())
  player.prepareAsync()
}

3. 서버에서 전달되는 음원 url 를 재생하는 경우

mediaPlayer.apply {
  setOnPreparedListener { player ->
    player.start()                
  }

  setOnCompletionListener {
    // 재새 완료 후 동작 처리...
  }

  setDataSource(url)
  prepareAsync()    
}

 

AudioTrack

PCM ByteArray Data 로 변환하여 AudioTrack 에 Writing 후 재생한다.

val minBufferSize = AudioTrack.getMinBufferSize(
  44100, // 각 음원에 맞는 SampleRate 설정...
  AudioFormat.CHANNEL_OUT_MONO,
  AudioFormat.ENCODING_PCM_16BIT
)

val audioTrack = AudioTrack(
  AudioAttributes.Builder()
    /**
    * 각 음원 Stream 에 맞는 타입을 설정한다.
    */
    .setUsage(AudioAttributes.USAGE_ASSISTANT)
    .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
    .build(),
  AudioFormat.Builder()
    .setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
    .setSampleRate(44100)
    .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
    .build(),
  minBufferSize,
  AudioTrack.MODE_STREAM,
  AudioManager.AUDIO_SESSION_ID_GENERATE
)

audioTrack.let { track ->
  track.play()
  var i1: Int
  val beep = ByteArray(minBufferSize)
  val inputStream: InputStream = context.openFileInput(FILE_NAME)
	
  if (track.state != AudioTrack.STATE_UNINITIALIZED) {
    if (track.playState != AudioTrack.PLAYSTATE_STOPPED) {
      try {
        while (inputStream.read(beep).also { i1 = it } != -1) {
          val written = track.write(beep, 0, i1)
          if (written <= AudioTrack.SUCCESS) {
            break
          }
        }

        // Track 재생 완료 후 처리....
      } catch (e: IOException) {
        Timber.tag(logTag).e("InterruptedException ${e.message}")
      }
    }
  }
}
728x90