Improve audio focus management (#4707)
* Extract Audio focus management to its own modules. * Request Audio focus when playing a voice message. * Add missing dependency. (and remove a duplicated one) * Request Audio focus when playing a video/audio in the media viewer. * Pause audio when audio focus is lost. * Rename class * Fix tests * Fix detekt issue. * Audio focus: let the system handle automatic ducking when playing media. * Document and update API * Remove useless space.
This commit is contained in:
parent
3cf8b04a07
commit
93499910ba
24 changed files with 341 additions and 49 deletions
|
|
@ -10,9 +10,6 @@ package io.element.android.features.call.impl.ui
|
|||
import android.Manifest
|
||||
import android.app.PictureInPictureParams
|
||||
import android.content.Intent
|
||||
import android.media.AudioAttributes
|
||||
import android.media.AudioFocusRequest
|
||||
import android.media.AudioManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Rational
|
||||
|
|
@ -46,6 +43,8 @@ import io.element.android.features.call.impl.utils.CallIntentDataParser
|
|||
import io.element.android.features.enterprise.api.EnterpriseService
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.bindings
|
||||
import io.element.android.libraries.audio.api.AudioFocus
|
||||
import io.element.android.libraries.audio.api.AudioFocusRequester
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.designsystem.theme.ElementThemeApp
|
||||
|
|
@ -65,16 +64,12 @@ class ElementCallActivity :
|
|||
@Inject lateinit var enterpriseService: EnterpriseService
|
||||
@Inject lateinit var pictureInPicturePresenter: PictureInPicturePresenter
|
||||
@Inject lateinit var buildMeta: BuildMeta
|
||||
@Inject lateinit var audioFocus: AudioFocus
|
||||
|
||||
private lateinit var presenter: Presenter<CallScreenState>
|
||||
|
||||
private lateinit var audioManager: AudioManager
|
||||
|
||||
private var requestPermissionCallback: RequestPermissionCallback? = null
|
||||
|
||||
private var audiofocusRequest: AudioFocusRequest? = null
|
||||
private var audioFocusChangeListener: AudioManager.OnAudioFocusChangeListener? = null
|
||||
|
||||
private val requestPermissionsLauncher = registerPermissionResultLauncher()
|
||||
|
||||
private val webViewTarget = mutableStateOf<CallType?>(null)
|
||||
|
|
@ -102,8 +97,6 @@ class ElementCallActivity :
|
|||
|
||||
pictureInPicturePresenter.setPipView(this)
|
||||
|
||||
audioManager = getSystemService(AUDIO_SERVICE) as AudioManager
|
||||
|
||||
setContent {
|
||||
val pipState = pictureInPicturePresenter.present()
|
||||
ListenToAndroidEvents(pipState)
|
||||
|
|
@ -133,7 +126,13 @@ class ElementCallActivity :
|
|||
}
|
||||
|
||||
private fun setCallIsActive() {
|
||||
requestAudioFocus()
|
||||
audioFocus.requestAudioFocus(
|
||||
requester = AudioFocusRequester.ElementCall,
|
||||
onFocusLost = {
|
||||
// If the audio focus is lost, we do not stop the call.
|
||||
Timber.tag(loggerTag.value).w("Audio focus lost")
|
||||
}
|
||||
)
|
||||
CallForegroundService.start(this)
|
||||
}
|
||||
|
||||
|
|
@ -175,7 +174,7 @@ class ElementCallActivity :
|
|||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
releaseAudioFocus()
|
||||
audioFocus.releaseAudioFocus()
|
||||
CallForegroundService.stop(this)
|
||||
pictureInPicturePresenter.setPipView(null)
|
||||
}
|
||||
|
|
@ -241,37 +240,6 @@ class ElementCallActivity :
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun requestAudioFocus() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val audioAttributes = AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
|
||||
.build()
|
||||
val request = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
|
||||
.setAudioAttributes(audioAttributes)
|
||||
.build()
|
||||
audioManager.requestAudioFocus(request)
|
||||
audiofocusRequest = request
|
||||
} else {
|
||||
val listener = AudioManager.OnAudioFocusChangeListener { }
|
||||
audioManager.requestAudioFocus(
|
||||
listener,
|
||||
AudioManager.STREAM_VOICE_CALL,
|
||||
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE,
|
||||
)
|
||||
audioFocusChangeListener = listener
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun releaseAudioFocus() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
audiofocusRequest?.let { audioManager.abandonAudioFocusRequest(it) }
|
||||
} else {
|
||||
audioFocusChangeListener?.let { audioManager.abandonAudioFocus(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
override fun setPipParams() {
|
||||
setPictureInPictureParams(getPictureInPictureParams())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue