handle audio focus and becoming noisy

Signed-off-by: parneet-guraya <gurayaparneet@gmail.com>
This commit is contained in:
parneet-guraya 2023-12-20 19:43:15 +05:30
parent 26f59c9a35
commit 91d5217b1e
No known key found for this signature in database
GPG key ID: 26DB680F1EE174D5
2 changed files with 100 additions and 21 deletions

View file

@ -42,7 +42,9 @@ import android.database.Cursor
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.media.AudioFocusRequest
import android.media.AudioFormat
import android.media.AudioManager
import android.media.AudioRecord
import android.media.MediaPlayer
import android.media.MediaRecorder
@ -384,6 +386,8 @@ class ChatActivity :
private var lastRecordMediaPosition: Int = 0
private var lastRecordedSeeked: Boolean = false
private val audioFocusChangeListener = getAudioFocusChangeListener()
private lateinit var participantPermissions: ParticipantPermissions
private var videoURI: Uri? = null
@ -1099,7 +1103,9 @@ class ChatActivity :
binding.messageInputView.micInputCloud.setOnClickListener {
if (mediaRecorderState == MediaRecorderState.RECORDING) {
recorder?.stop()
audioFocusRequest(false) {
recorder?.stop()
}
mediaRecorderState = MediaRecorderState.INITIAL
stopMicInputRecordingAnimation()
showPreviewVoiceRecording(true)
@ -1328,8 +1334,10 @@ class ChatActivity :
duration = it.duration.toLong()
interpolator = LinearInterpolator()
}
voicePreviewMediaPlayer!!.start()
voicePreviewObjectAnimator!!.start()
audioFocusRequest(true) {
voicePreviewMediaPlayer!!.start()
voicePreviewObjectAnimator!!.start()
}
}
setOnCompletionListener {
@ -1343,15 +1351,19 @@ class ChatActivity :
if (voicePreviewMediaPlayer == null) {
initPreviewVoiceRecording()
} else {
voicePreviewMediaPlayer!!.start()
voicePreviewObjectAnimator!!.resume()
audioFocusRequest(true) {
voicePreviewMediaPlayer!!.start()
voicePreviewObjectAnimator!!.resume()
}
}
}
private fun pausePreviewVoicePlaying() {
Log.d(TAG, "paused preview voice recording")
voicePreviewMediaPlayer!!.pause()
voicePreviewObjectAnimator!!.pause()
audioFocusRequest(false) {
voicePreviewMediaPlayer!!.pause()
voicePreviewObjectAnimator!!.pause()
}
}
private fun stopPreviewVoicePlaying() {
@ -1361,9 +1373,11 @@ class ChatActivity :
voicePreviewObjectAnimator!!.end()
voicePreviewObjectAnimator = null
binding.messageInputView.seekBar.clearAnimation()
voicePreviewMediaPlayer!!.stop()
voicePreviewMediaPlayer!!.release()
voicePreviewMediaPlayer = null
audioFocusRequest(false) {
voicePreviewMediaPlayer!!.stop()
voicePreviewMediaPlayer!!.release()
voicePreviewMediaPlayer = null
}
}
}
@ -1817,6 +1831,56 @@ class ChatActivity :
}
}
private fun getAudioFocusChangeListener(): AudioManager.OnAudioFocusChangeListener {
return AudioManager.OnAudioFocusChangeListener { flag ->
when (flag) {
AudioManager.AUDIOFOCUS_LOSS -> {
if (isVoicePreviewPlaying) {
stopPreviewVoicePlaying()
}
if (currentlyPlayedVoiceMessage != null) {
stopMediaPlayer(currentlyPlayedVoiceMessage!!)
}
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
if (isVoicePreviewPlaying) {
pausePreviewVoicePlaying()
}
if (currentlyPlayedVoiceMessage != null) {
pausePlayback(currentlyPlayedVoiceMessage!!)
}
}
}
}
}
private fun audioFocusRequest(shouldRequestFocus: Boolean, onGranted: () -> Unit) {
val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
val duration = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
val isGranted: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val focusRequest = AudioFocusRequest.Builder(duration)
.setOnAudioFocusChangeListener(audioFocusChangeListener)
.build()
if (shouldRequestFocus) {
audioManager.requestAudioFocus(focusRequest)
} else {
audioManager.abandonAudioFocusRequest(focusRequest)
}
} else {
@Deprecated("This method was deprecated in API level 26.")
if (shouldRequestFocus) {
audioManager.requestAudioFocus(audioFocusChangeListener, AudioManager.STREAM_MUSIC, duration)
} else {
audioManager.abandonAudioFocus(audioFocusChangeListener)
}
}
if (isGranted == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
onGranted()
}
}
private fun startPlayback(message: ChatMessage) {
if (!active) {
// don't begin to play voice message if screen is not visible anymore.
@ -1830,8 +1894,9 @@ class ChatActivity :
mediaPlayer?.let {
if (!it.isPlaying) {
it.start()
Log.d(TAG, "MediaPlayer has Started")
audioFocusRequest(true) {
it.start()
}
}
mediaPlayerHandler = Handler()
@ -1866,8 +1931,9 @@ class ChatActivity :
private fun pausePlayback(message: ChatMessage) {
if (mediaPlayer!!.isPlaying) {
mediaPlayer!!.pause()
Log.d(TAG, "MediaPlayer is paused")
audioFocusRequest(false) {
mediaPlayer!!.pause()
}
}
message.isPlayingVoiceMessage = false
@ -1925,7 +1991,9 @@ class ChatActivity :
mediaPlayer?.let {
if (it.isPlaying) {
Log.d(TAG, "media player is stopped")
it.stop()
audioFocusRequest(false) {
it.stop()
}
}
}
} catch (e: IllegalStateException) {
@ -2141,8 +2209,10 @@ class ChatActivity :
private fun stopMicInputRecordingAnimation() {
if (micInputAudioRecordThread != null) {
Log.d(TAG, "Mic Animation Ended")
micInputAudioRecorder.stop()
micInputAudioRecorder.release()
audioFocusRequest(false) {
micInputAudioRecorder.stop()
micInputAudioRecorder.release()
}
isMicInputAudioThreadRunning = false
micInputAudioRecordThread = null
}
@ -2193,7 +2263,9 @@ class ChatActivity :
}
try {
start()
audioFocusRequest(true) {
start()
}
mediaRecorderState = MediaRecorderState.RECORDING
Log.d(TAG, "recording started")
} catch (e: IllegalStateException) {
@ -2234,8 +2306,10 @@ class ChatActivity :
recorder?.apply {
try {
if (mediaRecorderState == MediaRecorderState.RECORDING) {
stop()
reset()
audioFocusRequest(false) {
stop()
reset()
}
mediaRecorderState = MediaRecorderState.INITIAL
Log.d(TAG, "stopped recorder")
}

View file

@ -44,6 +44,7 @@ import androidx.core.view.marginBottom
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.fragment.app.DialogFragment
import androidx.media3.common.AudioAttributes
import androidx.media3.common.MediaItem
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
@ -165,7 +166,10 @@ class FullScreenMediaActivity : AppCompatActivity() {
}
private fun initializePlayer() {
player = ExoPlayer.Builder(applicationContext).build()
player = ExoPlayer.Builder(applicationContext)
.setAudioAttributes(AudioAttributes.DEFAULT, true)
.setHandleAudioBecomingNoisy(true)
.build()
binding.playerView.player = player
}
@ -202,6 +206,7 @@ class FullScreenMediaActivity : AppCompatActivity() {
windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
supportActionBar?.show()
}
private fun applyWindowInsets() {
val playerView = binding.playerView
val exoControls = playerView.findViewById<FrameLayout>(R.id.exo_bottom_bar)