Request & release audio focus during voice recordings playback

This commit is contained in:
Sylvain Berfini 2021-07-15 13:49:51 +02:00
parent 536e78e98e
commit a9daf53d69
3 changed files with 71 additions and 0 deletions

View file

@ -26,6 +26,7 @@ import android.text.Spanned
import android.text.style.UnderlineSpan import android.text.style.UnderlineSpan
import android.widget.Toast import android.widget.Toast
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.media.AudioFocusRequestCompat
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
import kotlinx.coroutines.* import kotlinx.coroutines.*
@ -73,6 +74,7 @@ class ChatMessageContentData(
val formattedDuration = MutableLiveData<String>() val formattedDuration = MutableLiveData<String>()
val voiceRecordPlayingPosition = MutableLiveData<Int>() val voiceRecordPlayingPosition = MutableLiveData<Int>()
val isVoiceRecordPlaying = MutableLiveData<Boolean>() val isVoiceRecordPlaying = MutableLiveData<Boolean>()
var voiceRecordPlayingAudioFocusRequest: AudioFocusRequestCompat? = null
val isAlone: Boolean val isAlone: Boolean
get() { get() {
@ -257,6 +259,11 @@ class ChatMessageContentData(
initVoiceRecordPlayer() initVoiceRecordPlayer()
} }
if (voiceRecordPlayingAudioFocusRequest == null) {
voiceRecordPlayingAudioFocusRequest = AppUtils.acquireAudioFocusForVoiceRecording(
coreContext.context
)
}
voiceRecordingPlayer.start() voiceRecordingPlayer.start()
isVoiceRecordPlaying.value = true isVoiceRecordPlaying.value = true
tickerFlow().onEach { tickerFlow().onEach {
@ -269,6 +276,13 @@ class ChatMessageContentData(
if (!isPlayerClosed()) { if (!isPlayerClosed()) {
voiceRecordingPlayer.pause() voiceRecordingPlayer.pause()
} }
val request = voiceRecordPlayingAudioFocusRequest
if (request != null) {
AppUtils.releaseAudioFocusForVoiceRecording(coreContext.context, request)
voiceRecordPlayingAudioFocusRequest = null
}
isVoiceRecordPlaying.value = false isVoiceRecordPlaying.value = false
} }

View file

@ -23,6 +23,7 @@ import android.widget.Toast
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.media.AudioFocusRequestCompat
import java.io.File import java.io.File
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@ -89,6 +90,8 @@ class ChatMessageSendingViewModel(private val chatRoom: ChatRoom) : ViewModel()
val voiceRecordPlayingPosition = MutableLiveData<Int>() val voiceRecordPlayingPosition = MutableLiveData<Int>()
var voiceRecordPlayingAudioFocusRequest: AudioFocusRequestCompat? = null
private lateinit var voiceRecordingPlayer: Player private lateinit var voiceRecordingPlayer: Player
private val playerListener = PlayerListener { private val playerListener = PlayerListener {
Log.i("[Chat Message Sending] End of file reached") Log.i("[Chat Message Sending] End of file reached")
@ -352,6 +355,12 @@ class ChatMessageSendingViewModel(private val chatRoom: ChatRoom) : ViewModel()
initVoiceRecordPlayer() initVoiceRecordPlayer()
} }
if (voiceRecordPlayingAudioFocusRequest == null) {
voiceRecordPlayingAudioFocusRequest = AppUtils.acquireAudioFocusForVoiceRecording(
coreContext.context
)
}
voiceRecordingPlayer.start() voiceRecordingPlayer.start()
isPlayingVoiceRecording.value = true isPlayingVoiceRecording.value = true
@ -366,6 +375,12 @@ class ChatMessageSendingViewModel(private val chatRoom: ChatRoom) : ViewModel()
voiceRecordingPlayer.pause() voiceRecordingPlayer.pause()
} }
val request = voiceRecordPlayingAudioFocusRequest
if (request != null) {
AppUtils.releaseAudioFocusForVoiceRecording(coreContext.context, request)
voiceRecordPlayingAudioFocusRequest = null
}
isPlayingVoiceRecording.value = false isPlayingVoiceRecording.value = false
} }
@ -415,6 +430,13 @@ class ChatMessageSendingViewModel(private val chatRoom: ChatRoom) : ViewModel()
voiceRecordPlayingPosition.value = 0 voiceRecordPlayingPosition.value = 0
voiceRecordingPlayer.close() voiceRecordingPlayer.close()
} }
val request = voiceRecordPlayingAudioFocusRequest
if (request != null) {
AppUtils.releaseAudioFocusForVoiceRecording(coreContext.context, request)
voiceRecordPlayingAudioFocusRequest = null
}
isPlayingVoiceRecording.value = false isPlayingVoiceRecording.value = false
} }

View file

@ -29,6 +29,9 @@ import android.text.format.Formatter.formatShortFileSize
import android.util.TypedValue import android.util.TypedValue
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.emoji.text.EmojiCompat import androidx.emoji.text.EmojiCompat
import androidx.media.AudioAttributesCompat
import androidx.media.AudioFocusRequestCompat
import androidx.media.AudioManagerCompat
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import java.util.* import java.util.*
@ -146,5 +149,37 @@ class AppUtils {
Log.i("[Media Volume] Current value is $currentVolume, max value is $maxVolume") Log.i("[Media Volume] Current value is $currentVolume, max value is $maxVolume")
return currentVolume <= maxVolume * 0.5 return currentVolume <= maxVolume * 0.5
} }
fun acquireAudioFocusForVoiceRecording(context: Context): AudioFocusRequestCompat {
val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
val audioAttrs = AudioAttributesCompat.Builder()
.setUsage(AudioAttributesCompat.USAGE_MEDIA)
.setContentType(AudioAttributesCompat.CONTENT_TYPE_SPEECH)
.build()
val request =
AudioFocusRequestCompat.Builder(AudioManagerCompat.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
.setAudioAttributes(audioAttrs)
.setOnAudioFocusChangeListener { }
.build()
when (AudioManagerCompat.requestAudioFocus(audioManager, request)) {
AudioManager.AUDIOFOCUS_REQUEST_GRANTED -> {
Log.i("[Audio Focus] Voice recording audio focus request granted")
}
AudioManager.AUDIOFOCUS_REQUEST_FAILED -> {
Log.w("[Audio Focus] Voice recording audio focus request failed")
}
AudioManager.AUDIOFOCUS_REQUEST_DELAYED -> {
Log.w("[Audio Focus] Voice recording audio focus request delayed")
}
}
return request
}
fun releaseAudioFocusForVoiceRecording(context: Context, request: AudioFocusRequestCompat) {
val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
AudioManagerCompat.abandonAudioFocusRequest(audioManager, request)
Log.i("[Audio Focus] Voice recording audio focus request abandoned")
}
} }
} }