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.BitmapDrawable
import android.graphics.drawable.ColorDrawable import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.media.AudioFocusRequest
import android.media.AudioFormat import android.media.AudioFormat
import android.media.AudioManager
import android.media.AudioRecord import android.media.AudioRecord
import android.media.MediaPlayer import android.media.MediaPlayer
import android.media.MediaRecorder import android.media.MediaRecorder
@ -384,6 +386,8 @@ class ChatActivity :
private var lastRecordMediaPosition: Int = 0 private var lastRecordMediaPosition: Int = 0
private var lastRecordedSeeked: Boolean = false private var lastRecordedSeeked: Boolean = false
private val audioFocusChangeListener = getAudioFocusChangeListener()
private lateinit var participantPermissions: ParticipantPermissions private lateinit var participantPermissions: ParticipantPermissions
private var videoURI: Uri? = null private var videoURI: Uri? = null
@ -1099,7 +1103,9 @@ class ChatActivity :
binding.messageInputView.micInputCloud.setOnClickListener { binding.messageInputView.micInputCloud.setOnClickListener {
if (mediaRecorderState == MediaRecorderState.RECORDING) { if (mediaRecorderState == MediaRecorderState.RECORDING) {
recorder?.stop() audioFocusRequest(false) {
recorder?.stop()
}
mediaRecorderState = MediaRecorderState.INITIAL mediaRecorderState = MediaRecorderState.INITIAL
stopMicInputRecordingAnimation() stopMicInputRecordingAnimation()
showPreviewVoiceRecording(true) showPreviewVoiceRecording(true)
@ -1328,8 +1334,10 @@ class ChatActivity :
duration = it.duration.toLong() duration = it.duration.toLong()
interpolator = LinearInterpolator() interpolator = LinearInterpolator()
} }
voicePreviewMediaPlayer!!.start() audioFocusRequest(true) {
voicePreviewObjectAnimator!!.start() voicePreviewMediaPlayer!!.start()
voicePreviewObjectAnimator!!.start()
}
} }
setOnCompletionListener { setOnCompletionListener {
@ -1343,15 +1351,19 @@ class ChatActivity :
if (voicePreviewMediaPlayer == null) { if (voicePreviewMediaPlayer == null) {
initPreviewVoiceRecording() initPreviewVoiceRecording()
} else { } else {
voicePreviewMediaPlayer!!.start() audioFocusRequest(true) {
voicePreviewObjectAnimator!!.resume() voicePreviewMediaPlayer!!.start()
voicePreviewObjectAnimator!!.resume()
}
} }
} }
private fun pausePreviewVoicePlaying() { private fun pausePreviewVoicePlaying() {
Log.d(TAG, "paused preview voice recording") Log.d(TAG, "paused preview voice recording")
voicePreviewMediaPlayer!!.pause() audioFocusRequest(false) {
voicePreviewObjectAnimator!!.pause() voicePreviewMediaPlayer!!.pause()
voicePreviewObjectAnimator!!.pause()
}
} }
private fun stopPreviewVoicePlaying() { private fun stopPreviewVoicePlaying() {
@ -1361,9 +1373,11 @@ class ChatActivity :
voicePreviewObjectAnimator!!.end() voicePreviewObjectAnimator!!.end()
voicePreviewObjectAnimator = null voicePreviewObjectAnimator = null
binding.messageInputView.seekBar.clearAnimation() binding.messageInputView.seekBar.clearAnimation()
voicePreviewMediaPlayer!!.stop() audioFocusRequest(false) {
voicePreviewMediaPlayer!!.release() voicePreviewMediaPlayer!!.stop()
voicePreviewMediaPlayer = null 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) { private fun startPlayback(message: ChatMessage) {
if (!active) { if (!active) {
// don't begin to play voice message if screen is not visible anymore. // don't begin to play voice message if screen is not visible anymore.
@ -1830,8 +1894,9 @@ class ChatActivity :
mediaPlayer?.let { mediaPlayer?.let {
if (!it.isPlaying) { if (!it.isPlaying) {
it.start() audioFocusRequest(true) {
Log.d(TAG, "MediaPlayer has Started") it.start()
}
} }
mediaPlayerHandler = Handler() mediaPlayerHandler = Handler()
@ -1866,8 +1931,9 @@ class ChatActivity :
private fun pausePlayback(message: ChatMessage) { private fun pausePlayback(message: ChatMessage) {
if (mediaPlayer!!.isPlaying) { if (mediaPlayer!!.isPlaying) {
mediaPlayer!!.pause() audioFocusRequest(false) {
Log.d(TAG, "MediaPlayer is paused") mediaPlayer!!.pause()
}
} }
message.isPlayingVoiceMessage = false message.isPlayingVoiceMessage = false
@ -1925,7 +1991,9 @@ class ChatActivity :
mediaPlayer?.let { mediaPlayer?.let {
if (it.isPlaying) { if (it.isPlaying) {
Log.d(TAG, "media player is stopped") Log.d(TAG, "media player is stopped")
it.stop() audioFocusRequest(false) {
it.stop()
}
} }
} }
} catch (e: IllegalStateException) { } catch (e: IllegalStateException) {
@ -2141,8 +2209,10 @@ class ChatActivity :
private fun stopMicInputRecordingAnimation() { private fun stopMicInputRecordingAnimation() {
if (micInputAudioRecordThread != null) { if (micInputAudioRecordThread != null) {
Log.d(TAG, "Mic Animation Ended") Log.d(TAG, "Mic Animation Ended")
micInputAudioRecorder.stop() audioFocusRequest(false) {
micInputAudioRecorder.release() micInputAudioRecorder.stop()
micInputAudioRecorder.release()
}
isMicInputAudioThreadRunning = false isMicInputAudioThreadRunning = false
micInputAudioRecordThread = null micInputAudioRecordThread = null
} }
@ -2193,7 +2263,9 @@ class ChatActivity :
} }
try { try {
start() audioFocusRequest(true) {
start()
}
mediaRecorderState = MediaRecorderState.RECORDING mediaRecorderState = MediaRecorderState.RECORDING
Log.d(TAG, "recording started") Log.d(TAG, "recording started")
} catch (e: IllegalStateException) { } catch (e: IllegalStateException) {
@ -2234,8 +2306,10 @@ class ChatActivity :
recorder?.apply { recorder?.apply {
try { try {
if (mediaRecorderState == MediaRecorderState.RECORDING) { if (mediaRecorderState == MediaRecorderState.RECORDING) {
stop() audioFocusRequest(false) {
reset() stop()
reset()
}
mediaRecorderState = MediaRecorderState.INITIAL mediaRecorderState = MediaRecorderState.INITIAL
Log.d(TAG, "stopped recorder") 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.updateLayoutParams
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.media3.common.AudioAttributes
import androidx.media3.common.MediaItem import androidx.media3.common.MediaItem
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.ExoPlayer
@ -165,7 +166,10 @@ class FullScreenMediaActivity : AppCompatActivity() {
} }
private fun initializePlayer() { private fun initializePlayer() {
player = ExoPlayer.Builder(applicationContext).build() player = ExoPlayer.Builder(applicationContext)
.setAudioAttributes(AudioAttributes.DEFAULT, true)
.setHandleAudioBecomingNoisy(true)
.build()
binding.playerView.player = player binding.playerView.player = player
} }
@ -202,6 +206,7 @@ class FullScreenMediaActivity : AppCompatActivity() {
windowInsetsController.show(WindowInsetsCompat.Type.systemBars()) windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
supportActionBar?.show() supportActionBar?.show()
} }
private fun applyWindowInsets() { private fun applyWindowInsets() {
val playerView = binding.playerView val playerView = binding.playerView
val exoControls = playerView.findViewById<FrameLayout>(R.id.exo_bottom_bar) val exoControls = playerView.findViewById<FrameLayout>(R.id.exo_bottom_bar)