From eb8b02756bf1f396e3ff12c014fcfcd93966eaf6 Mon Sep 17 00:00:00 2001 From: Koen J <koen@disper.io> Date: Tue, 3 Sep 2024 11:13:23 +0200 Subject: [PATCH] Fixed case where device fails to acquire audio focus. --- .../services/MediaPlaybackService.kt | 65 ++++++++++++------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/futo/platformplayer/services/MediaPlaybackService.kt b/app/src/main/java/com/futo/platformplayer/services/MediaPlaybackService.kt index e12e24af..928db6d8 100644 --- a/app/src/main/java/com/futo/platformplayer/services/MediaPlaybackService.kt +++ b/app/src/main/java/com/futo/platformplayer/services/MediaPlaybackService.kt @@ -58,6 +58,8 @@ class MediaPlaybackService : Service() { private var _focusRequest: AudioFocusRequest? = null; private var _audioFocusLossTime_ms: Long? = null private var _playbackState = PlaybackStateCompat.STATE_NONE; + private val _handler = Handler(Looper.getMainLooper()) + private val _audioFocusRunnable = Runnable { setAudioFocus(false) } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Logger.v(TAG, "onStartCommand"); @@ -161,6 +163,8 @@ class MediaPlaybackService : Service() { val focusRequest = _focusRequest; if (focusRequest != null) { + Logger.i(TAG, "Audio focus abandoned") + _handler.removeCallbacks(_audioFocusRunnable) _audioManager?.abandonAudioFocusRequest(focusRequest); _focusRequest = null; } @@ -342,22 +346,46 @@ class MediaPlaybackService : Service() { } //TODO: (TBD) This code probably more fitting inside FutoVideoPlayer, as this service is generally only used for global events - private fun setAudioFocus() { - Log.i(TAG, "Requested audio focus."); + private fun setAudioFocus(createFocusRequest: Boolean = true) { + _handler.removeCallbacks(_audioFocusRunnable) - val focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN) - .setAcceptsDelayedFocusGain(true) - .setOnAudioFocusChangeListener(_audioFocusChangeListener) - .build() + if (_hasFocus) { + Log.i(TAG, "Skipped trying to get audio focus because audio focus is already obtained."); + return; + } + + if (_focusRequest == null) { + if (!createFocusRequest) { + Log.i(TAG, "Skipped trying to get audio focus because createFocusRequest = false and no focus request exists."); + return; + } + + val focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN) + .setAcceptsDelayedFocusGain(true) + .setOnAudioFocusChangeListener(_audioFocusChangeListener) + .build() - _focusRequest = focusRequest; - val result = _audioManager?.requestAudioFocus(focusRequest) + _focusRequest = focusRequest; + Log.i(TAG, "Created audio focus request."); + } + + Log.i(TAG, "Requesting audio focus."); + + val result = _audioManager?.requestAudioFocus(_focusRequest!!) Log.i(TAG, "Audio focus request result $result"); if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { - //TODO: Handle when not possible to get audio focus _hasFocus = true; Log.i(TAG, "Audio focus received"); + } else if (result == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) { + _hasFocus = false + Log.i(TAG, "Audio focus delayed, waiting for focus") + } else { + _hasFocus = false + Log.i(TAG, "Audio focus not granted, retrying in 1 second") + _handler.postDelayed(_audioFocusRunnable, 1000) } + + Log.i(TAG, "Audio focus requested."); } private val _audioFocusChangeListener = @@ -365,8 +393,7 @@ class MediaPlaybackService : Service() { try { when (focusChange) { AudioManager.AUDIOFOCUS_GAIN -> { - //Do not start playing on gaining audo focus - //MediaControlReceiver.onPlayReceived.emit(); + _handler.removeCallbacks(_audioFocusRunnable) _hasFocus = true; Log.i(TAG, "Audio focus gained (restartPlaybackAfterLoss = ${Settings.instance.playback.restartPlaybackAfterLoss}, _audioFocusLossTime_ms = $_audioFocusLossTime_ms)"); @@ -385,7 +412,6 @@ class MediaPlaybackService : Service() { } } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { - MediaControlReceiver.onPauseReceived.emit(); if (_playbackState != PlaybackStateCompat.STATE_PAUSED && _playbackState != PlaybackStateCompat.STATE_STOPPED && _playbackState != PlaybackStateCompat.STATE_NONE && @@ -393,10 +419,13 @@ class MediaPlaybackService : Service() { _audioFocusLossTime_ms = System.currentTimeMillis() } - Log.i(TAG, "Audio focus transient loss"); + _hasFocus = false; + MediaControlReceiver.onPauseReceived.emit(); + Log.i(TAG, "Audio focus transient loss (_audioFocusLossTime_ms = ${_audioFocusLossTime_ms})"); } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { Log.i(TAG, "Audio focus transient loss, can duck"); + _hasFocus = true; } AudioManager.AUDIOFOCUS_LOSS -> { if (_playbackState != PlaybackStateCompat.STATE_PAUSED && @@ -409,16 +438,6 @@ class MediaPlaybackService : Service() { _hasFocus = false; MediaControlReceiver.onPauseReceived.emit(); Log.i(TAG, "Audio focus lost"); - - val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager - val runningAppProcesses = activityManager.runningAppProcesses - for (processInfo in runningAppProcesses) { - // Check the importance of the running app process - if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { - // This app is in the foreground, which might have caused the loss of audio focus - Log.i("AudioFocus", "App ${processInfo.processName} might have caused the loss of audio focus") - } - } } } } catch(ex: Throwable) { -- GitLab