Commit 1c03226f by tonihei Committed by Oliver Woodman

Merge AudioFocusManager methods to simplify control flow.

handlePrepare/Stop/SetPlayReady can be merged together as they all
handle changes to the desires state of the player.

Also, simplify parts of the control flow by not mixing code that
determines if audio focus needs to be handled with code that actually
acquires or abandons the focus.

PiperOrigin-RevId: 299824857
parent 1ac7d377
...@@ -24,7 +24,6 @@ import androidx.annotation.Nullable; ...@@ -24,7 +24,6 @@ import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
...@@ -134,64 +133,38 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -134,64 +133,38 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** /**
* Sets audio attributes that should be used to manage audio focus. * Sets audio attributes that should be used to manage audio focus.
* *
* <p>Call {@link #updateAudioFocus(boolean, int)} to update the audio focus based on these
* attributes.
*
* @param audioAttributes The audio attributes or {@code null} if audio focus should not be * @param audioAttributes The audio attributes or {@code null} if audio focus should not be
* managed automatically. * managed automatically.
* @param playWhenReady The current state of {@link ExoPlayer#getPlayWhenReady()}.
* @param playerState The current player state; {@link ExoPlayer#getPlaybackState()}.
* @return A {@link PlayerCommand} to execute on the player.
*/ */
@PlayerCommand public void setAudioAttributes(@Nullable AudioAttributes audioAttributes) {
public int setAudioAttributes(
@Nullable AudioAttributes audioAttributes, boolean playWhenReady, int playerState) {
if (!Util.areEqual(this.audioAttributes, audioAttributes)) { if (!Util.areEqual(this.audioAttributes, audioAttributes)) {
this.audioAttributes = audioAttributes; this.audioAttributes = audioAttributes;
focusGain = convertAudioAttributesToFocusGain(audioAttributes); focusGain = convertAudioAttributesToFocusGain(audioAttributes);
Assertions.checkArgument( Assertions.checkArgument(
focusGain == C.AUDIOFOCUS_GAIN || focusGain == C.AUDIOFOCUS_NONE, focusGain == C.AUDIOFOCUS_GAIN || focusGain == C.AUDIOFOCUS_NONE,
"Automatic handling of audio focus is only available for USAGE_MEDIA and USAGE_GAME."); "Automatic handling of audio focus is only available for USAGE_MEDIA and USAGE_GAME.");
if (playWhenReady
&& (playerState == Player.STATE_BUFFERING || playerState == Player.STATE_READY)) {
return requestAudioFocus();
}
} }
return playerState == Player.STATE_IDLE
? handleIdle(playWhenReady)
: handlePrepare(playWhenReady);
} }
/** /**
* Called by a player as part of {@link ExoPlayer#prepare(MediaSource, boolean, boolean)}. * Called by the player to abandon or request audio focus based on the desired player state.
*
* @param playWhenReady The current state of {@link ExoPlayer#getPlayWhenReady()}.
* @return A {@link PlayerCommand} to execute on the player.
*/
@PlayerCommand
public int handlePrepare(boolean playWhenReady) {
return playWhenReady ? requestAudioFocus() : PLAYER_COMMAND_DO_NOT_PLAY;
}
/**
* Called by the player as part of {@link ExoPlayer#setPlayWhenReady(boolean)}.
* *
* @param playWhenReady The desired value of playWhenReady. * @param playWhenReady The desired value of playWhenReady.
* @param playerState The current state of the player. * @param playbackState The desired playback state.
* @return A {@link PlayerCommand} to execute on the player. * @return A {@link PlayerCommand} to execute on the player.
*/ */
@PlayerCommand @PlayerCommand
public int handleSetPlayWhenReady(boolean playWhenReady, int playerState) { public int updateAudioFocus(boolean playWhenReady, @Player.State int playbackState) {
if (!playWhenReady) { if (!shouldHandleAudioFocus(playbackState)) {
abandonAudioFocus(); if (audioFocusState != AUDIO_FOCUS_STATE_NO_FOCUS) {
return PLAYER_COMMAND_DO_NOT_PLAY; abandonAudioFocus();
}
return playWhenReady ? PLAYER_COMMAND_PLAY_WHEN_READY : PLAYER_COMMAND_DO_NOT_PLAY;
} }
return playWhenReady ? requestAudioFocus() : PLAYER_COMMAND_DO_NOT_PLAY;
return playerState == Player.STATE_IDLE ? handleIdle(playWhenReady) : requestAudioFocus();
}
/** Called by the player as part of {@link ExoPlayer#stop(boolean)}. */
public void handleStop() {
abandonAudioFocus(/* forceAbandon= */ true);
} }
// Internal methods. // Internal methods.
...@@ -201,22 +174,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -201,22 +174,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
return focusListener; return focusListener;
} }
@PlayerCommand private boolean shouldHandleAudioFocus(@Player.State int playbackState) {
private int handleIdle(boolean playWhenReady) { return playbackState != Player.STATE_IDLE && focusGain == C.AUDIOFOCUS_GAIN;
return playWhenReady ? PLAYER_COMMAND_PLAY_WHEN_READY : PLAYER_COMMAND_DO_NOT_PLAY;
} }
@PlayerCommand @PlayerCommand
private int requestAudioFocus() { private int requestAudioFocus() {
int focusRequestResult; int focusRequestResult;
if (focusGain == C.AUDIOFOCUS_NONE) {
if (audioFocusState != AUDIO_FOCUS_STATE_NO_FOCUS) {
abandonAudioFocus(/* forceAbandon= */ true);
}
return PLAYER_COMMAND_PLAY_WHEN_READY;
}
if (audioFocusState == AUDIO_FOCUS_STATE_NO_FOCUS) { if (audioFocusState == AUDIO_FOCUS_STATE_NO_FOCUS) {
if (Util.SDK_INT >= 26) { if (Util.SDK_INT >= 26) {
focusRequestResult = requestAudioFocusV26(); focusRequestResult = requestAudioFocusV26();
...@@ -239,24 +204,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -239,24 +204,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} }
private void abandonAudioFocus() { private void abandonAudioFocus() {
abandonAudioFocus(/* forceAbandon= */ false); if (audioFocusState == AUDIO_FOCUS_STATE_NO_FOCUS) {
}
private void abandonAudioFocus(boolean forceAbandon) {
if (focusGain == C.AUDIOFOCUS_NONE && audioFocusState == AUDIO_FOCUS_STATE_NO_FOCUS) {
return; return;
} }
if (Util.SDK_INT >= 26) {
if (focusGain != C.AUDIOFOCUS_GAIN abandonAudioFocusV26();
|| audioFocusState == AUDIO_FOCUS_STATE_LOST_FOCUS } else {
|| forceAbandon) { abandonAudioFocusDefault();
if (Util.SDK_INT >= 26) {
abandonAudioFocusV26();
} else {
abandonAudioFocusDefault();
}
audioFocusState = AUDIO_FOCUS_STATE_NO_FOCUS;
} }
audioFocusState = AUDIO_FOCUS_STATE_NO_FOCUS;
} }
private int requestAudioFocusDefault() { private int requestAudioFocusDefault() {
...@@ -312,7 +268,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -312,7 +268,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
*/ */
@C.AudioFocusGain @C.AudioFocusGain
private static int convertAudioAttributesToFocusGain(@Nullable AudioAttributes audioAttributes) { private static int convertAudioAttributesToFocusGain(@Nullable AudioAttributes audioAttributes) {
if (audioAttributes == null) { if (audioAttributes == null) {
// Don't handle audio focus. It may be either video only contents or developers // Don't handle audio focus. It may be either video only contents or developers
// want to have more finer grained control. (e.g. adding audio focus listener) // want to have more finer grained control. (e.g. adding audio focus listener)
...@@ -414,7 +369,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -414,7 +369,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
break; break;
case AUDIO_FOCUS_STATE_LOST_FOCUS: case AUDIO_FOCUS_STATE_LOST_FOCUS:
playerControl.executePlayerCommand(PLAYER_COMMAND_DO_NOT_PLAY); playerControl.executePlayerCommand(PLAYER_COMMAND_DO_NOT_PLAY);
abandonAudioFocus(/* forceAbandon= */ true); abandonAudioFocus();
break; break;
case AUDIO_FOCUS_STATE_LOSS_TRANSIENT: case AUDIO_FOCUS_STATE_LOSS_TRANSIENT:
playerControl.executePlayerCommand(PLAYER_COMMAND_WAIT_FOR_CALLBACK); playerControl.executePlayerCommand(PLAYER_COMMAND_WAIT_FOR_CALLBACK);
......
...@@ -658,11 +658,10 @@ public class SimpleExoPlayer extends BasePlayer ...@@ -658,11 +658,10 @@ public class SimpleExoPlayer extends BasePlayer
} }
} }
audioFocusManager.setAudioAttributes(handleAudioFocus ? audioAttributes : null);
boolean playWhenReady = getPlayWhenReady(); boolean playWhenReady = getPlayWhenReady();
@AudioFocusManager.PlayerCommand @AudioFocusManager.PlayerCommand
int playerCommand = int playerCommand = audioFocusManager.updateAudioFocus(playWhenReady, getPlaybackState());
audioFocusManager.setAudioAttributes(
handleAudioFocus ? audioAttributes : null, playWhenReady, getPlaybackState());
updatePlayWhenReady( updatePlayWhenReady(
playWhenReady, playerCommand, getPlayWhenReadyChangeReason(playWhenReady, playerCommand)); playWhenReady, playerCommand, getPlayWhenReadyChangeReason(playWhenReady, playerCommand));
} }
...@@ -1205,7 +1204,7 @@ public class SimpleExoPlayer extends BasePlayer ...@@ -1205,7 +1204,7 @@ public class SimpleExoPlayer extends BasePlayer
verifyApplicationThread(); verifyApplicationThread();
boolean playWhenReady = getPlayWhenReady(); boolean playWhenReady = getPlayWhenReady();
@AudioFocusManager.PlayerCommand @AudioFocusManager.PlayerCommand
int playerCommand = audioFocusManager.handlePrepare(playWhenReady); int playerCommand = audioFocusManager.updateAudioFocus(playWhenReady, Player.STATE_BUFFERING);
updatePlayWhenReady( updatePlayWhenReady(
playWhenReady, playerCommand, getPlayWhenReadyChangeReason(playWhenReady, playerCommand)); playWhenReady, playerCommand, getPlayWhenReadyChangeReason(playWhenReady, playerCommand));
player.prepare(); player.prepare();
...@@ -1343,7 +1342,7 @@ public class SimpleExoPlayer extends BasePlayer ...@@ -1343,7 +1342,7 @@ public class SimpleExoPlayer extends BasePlayer
public void setPlayWhenReady(boolean playWhenReady) { public void setPlayWhenReady(boolean playWhenReady) {
verifyApplicationThread(); verifyApplicationThread();
@AudioFocusManager.PlayerCommand @AudioFocusManager.PlayerCommand
int playerCommand = audioFocusManager.handleSetPlayWhenReady(playWhenReady, getPlaybackState()); int playerCommand = audioFocusManager.updateAudioFocus(playWhenReady, getPlaybackState());
updatePlayWhenReady( updatePlayWhenReady(
playWhenReady, playerCommand, getPlayWhenReadyChangeReason(playWhenReady, playerCommand)); playWhenReady, playerCommand, getPlayWhenReadyChangeReason(playWhenReady, playerCommand));
} }
...@@ -1432,8 +1431,8 @@ public class SimpleExoPlayer extends BasePlayer ...@@ -1432,8 +1431,8 @@ public class SimpleExoPlayer extends BasePlayer
@Override @Override
public void stop(boolean reset) { public void stop(boolean reset) {
verifyApplicationThread(); verifyApplicationThread();
audioFocusManager.updateAudioFocus(getPlayWhenReady(), Player.STATE_IDLE);
player.stop(reset); player.stop(reset);
audioFocusManager.handleStop();
currentCues = Collections.emptyList(); currentCues = Collections.emptyList();
} }
...@@ -1441,7 +1440,7 @@ public class SimpleExoPlayer extends BasePlayer ...@@ -1441,7 +1440,7 @@ public class SimpleExoPlayer extends BasePlayer
public void release() { public void release() {
verifyApplicationThread(); verifyApplicationThread();
audioBecomingNoisyManager.setEnabled(false); audioBecomingNoisyManager.setEnabled(false);
audioFocusManager.handleStop(); audioFocusManager.updateAudioFocus(/* playWhenReady= */ false, Player.STATE_IDLE);
wakeLockManager.setStayAwake(false); wakeLockManager.setStayAwake(false);
wifiLockManager.setStayAwake(false); wifiLockManager.setStayAwake(false);
player.release(); player.release();
...@@ -2011,13 +2010,9 @@ public class SimpleExoPlayer extends BasePlayer ...@@ -2011,13 +2010,9 @@ public class SimpleExoPlayer extends BasePlayer
@Override @Override
public void onAudioBecomingNoisy() { public void onAudioBecomingNoisy() {
// Command is always PLAYER_COMMAND_DO_NOT_PLAY but the call is needed to abandon the
// audio focus if the focus is currently held.
int playerCommand =
audioFocusManager.handleSetPlayWhenReady(/* playWhenReady= */ false, getPlaybackState());
updatePlayWhenReady( updatePlayWhenReady(
/* playWhenReady= */ false, /* playWhenReady= */ false,
playerCommand, AudioFocusManager.PLAYER_COMMAND_DO_NOT_PLAY,
Player.PLAY_WHEN_READY_CHANGE_REASON_AUDIO_BECOMING_NOISY); Player.PLAY_WHEN_READY_CHANGE_REASON_AUDIO_BECOMING_NOISY);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment