Merge pull request #6247 from ByteHamster/rewrite-audio-focus

Rework audio focus handling
This commit is contained in:
ByteHamster 2022-12-20 21:18:48 +01:00 committed by GitHub
commit 0776f232d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -4,9 +4,10 @@ import android.app.UiModeManager;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.media.AudioManager; import android.media.AudioManager;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager; import android.os.PowerManager;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import android.telephony.TelephonyManager;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
@ -44,7 +45,6 @@ import de.danoeh.antennapod.playback.base.RewindAfterPauseUtils;
import de.danoeh.antennapod.core.util.playback.AudioPlayer; import de.danoeh.antennapod.core.util.playback.AudioPlayer;
import de.danoeh.antennapod.core.util.playback.IPlayer; import de.danoeh.antennapod.core.util.playback.IPlayer;
import de.danoeh.antennapod.model.playback.Playable; import de.danoeh.antennapod.model.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
import de.danoeh.antennapod.core.util.playback.VideoPlayer; import de.danoeh.antennapod.core.util.playback.VideoPlayer;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
@ -66,6 +66,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
private volatile boolean pausedBecauseOfTransientAudiofocusLoss; private volatile boolean pausedBecauseOfTransientAudiofocusLoss;
private volatile Pair<Integer, Integer> videoSize; private volatile Pair<Integer, Integer> videoSize;
private final AudioFocusRequestCompat audioFocusRequest; private final AudioFocusRequestCompat audioFocusRequest;
private final Handler audioFocusCanceller;
/** /**
* Some asynchronous calls might change the state of the MediaPlayer object. Therefore calls in other threads * Some asynchronous calls might change the state of the MediaPlayer object. Therefore calls in other threads
@ -154,6 +155,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
this.audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); this.audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
this.playerLock = new PlayerLock(); this.playerLock = new PlayerLock();
this.startWhenPrepared = new AtomicBoolean(false); this.startWhenPrepared = new AtomicBoolean(false);
audioFocusCanceller = new Handler(Looper.getMainLooper());
executor = new PlayerExecutor(); executor = new PlayerExecutor();
executor.threadPool = new ThreadPoolExecutor(1, 1, 5, TimeUnit.MINUTES, new LinkedBlockingDeque<>(), executor.threadPool = new ThreadPoolExecutor(1, 1, 5, TimeUnit.MINUTES, new LinkedBlockingDeque<>(),
@ -853,53 +855,46 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
if (!PlaybackService.isRunning) { if (!PlaybackService.isRunning) {
abandonAudioFocus(); abandonAudioFocus();
Log.d(TAG, "onAudioFocusChange: PlaybackService is no longer running"); Log.d(TAG, "onAudioFocusChange: PlaybackService is no longer running");
if (focusChange == AudioManager.AUDIOFOCUS_GAIN && pausedBecauseOfTransientAudiofocusLoss) {
pausedBecauseOfTransientAudiofocusLoss = false;
new PlaybackServiceStarter(context, getPlayable())
.callEvenIfRunning(false)
.start();
}
return; return;
} }
executor.submit(() -> { executor.submit(() -> {
playerLock.lock(); playerLock.lock();
if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
// If there is an incoming call, playback should be paused permanently
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
final int callState = (tm != null) ? tm.getCallState() : 0;
Log.i(TAG, "Call state:" + callState);
if (focusChange == AudioManager.AUDIOFOCUS_LOSS ||
(!UserPreferences.shouldResumeAfterCall() && callState != TelephonyManager.CALL_STATE_IDLE)) {
Log.d(TAG, "Lost audio focus"); Log.d(TAG, "Lost audio focus");
pause(true, false); pause(true, false);
callback.shouldStop(); callback.shouldStop();
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
&& !UserPreferences.shouldPauseForFocusLoss()) {
if (playerStatus == PlayerStatus.PLAYING) {
Log.d(TAG, "Lost audio focus temporarily. Ducking...");
setVolumeSync(0.25f, 0.25f);
pausedBecauseOfTransientAudiofocusLoss = false;
}
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT
|| focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
if (playerStatus == PlayerStatus.PLAYING) {
Log.d(TAG, "Lost audio focus temporarily. Pausing...");
mediaPlayer.pause(); // Pause without telling the PlaybackService
pausedBecauseOfTransientAudiofocusLoss = true;
audioFocusCanceller.removeCallbacksAndMessages(null);
audioFocusCanceller.postDelayed(() -> {
if (pausedBecauseOfTransientAudiofocusLoss) {
// Still did not get back the audio focus. Now actually pause.
pause(true, false);
}
}, 10000);
}
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
Log.d(TAG, "Gained audio focus"); Log.d(TAG, "Gained audio focus");
audioFocusCanceller.removeCallbacksAndMessages(null);
if (pausedBecauseOfTransientAudiofocusLoss) { // we paused => play now if (pausedBecauseOfTransientAudiofocusLoss) { // we paused => play now
resume(); mediaPlayer.start();
} else { // we ducked => raise audio level back } else { // we ducked => raise audio level back
setVolumeSync(1.0f, 1.0f); setVolumeSync(1.0f, 1.0f);
} }
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { pausedBecauseOfTransientAudiofocusLoss = false;
if (playerStatus == PlayerStatus.PLAYING) {
if (!UserPreferences.shouldPauseForFocusLoss()) {
Log.d(TAG, "Lost audio focus temporarily. Ducking...");
setVolumeSync(0.25f, 0.25f);
pausedBecauseOfTransientAudiofocusLoss = false;
} else {
Log.d(TAG, "Lost audio focus temporarily. Could duck, but won't, pausing...");
pause(false, false);
pausedBecauseOfTransientAudiofocusLoss = true;
}
}
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
if (playerStatus == PlayerStatus.PLAYING) {
Log.d(TAG, "Lost audio focus temporarily. Pausing...");
pause(false, false);
pausedBecauseOfTransientAudiofocusLoss = true;
}
} }
playerLock.unlock(); playerLock.unlock();
}); });