mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Fix audio focus handling in ExoPlayerImpl
Some cases are not handled correctly at the moment: - Pausing during suppressed playback should not clear the suppression state. - Transient focus loss while paused should be reported as a playback suppression. Issue: androidx/media#1436 #cherrypick PiperOrigin-RevId: 644971218
This commit is contained in:
parent
1d26d1891e
commit
e84bb0d21c
@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
* Common Library:
|
* Common Library:
|
||||||
* ExoPlayer:
|
* ExoPlayer:
|
||||||
|
* Fix some audio focus inconsistencies, e.g. not reporting full or
|
||||||
|
transient focus loss while the player is paused
|
||||||
|
([#1436](https://github.com/androidx/media/issues/1436)).
|
||||||
* Transformer:
|
* Transformer:
|
||||||
* Track Selection:
|
* Track Selection:
|
||||||
* Extractors:
|
* Extractors:
|
||||||
|
@ -550,8 +550,7 @@ import java.util.concurrent.TimeoutException;
|
|||||||
boolean playWhenReady = getPlayWhenReady();
|
boolean playWhenReady = getPlayWhenReady();
|
||||||
@AudioFocusManager.PlayerCommand
|
@AudioFocusManager.PlayerCommand
|
||||||
int playerCommand = audioFocusManager.updateAudioFocus(playWhenReady, Player.STATE_BUFFERING);
|
int playerCommand = audioFocusManager.updateAudioFocus(playWhenReady, Player.STATE_BUFFERING);
|
||||||
updatePlayWhenReady(
|
updatePlayWhenReady(playWhenReady, playerCommand, getPlayWhenReadyChangeReason(playerCommand));
|
||||||
playWhenReady, playerCommand, getPlayWhenReadyChangeReason(playWhenReady, playerCommand));
|
|
||||||
if (playbackInfo.playbackState != Player.STATE_IDLE) {
|
if (playbackInfo.playbackState != Player.STATE_IDLE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -831,8 +830,7 @@ import java.util.concurrent.TimeoutException;
|
|||||||
verifyApplicationThread();
|
verifyApplicationThread();
|
||||||
@AudioFocusManager.PlayerCommand
|
@AudioFocusManager.PlayerCommand
|
||||||
int playerCommand = audioFocusManager.updateAudioFocus(playWhenReady, getPlaybackState());
|
int playerCommand = audioFocusManager.updateAudioFocus(playWhenReady, getPlaybackState());
|
||||||
updatePlayWhenReady(
|
updatePlayWhenReady(playWhenReady, playerCommand, getPlayWhenReadyChangeReason(playerCommand));
|
||||||
playWhenReady, playerCommand, getPlayWhenReadyChangeReason(playWhenReady, playerCommand));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1500,8 +1498,7 @@ import java.util.concurrent.TimeoutException;
|
|||||||
boolean playWhenReady = getPlayWhenReady();
|
boolean playWhenReady = getPlayWhenReady();
|
||||||
@AudioFocusManager.PlayerCommand
|
@AudioFocusManager.PlayerCommand
|
||||||
int playerCommand = audioFocusManager.updateAudioFocus(playWhenReady, getPlaybackState());
|
int playerCommand = audioFocusManager.updateAudioFocus(playWhenReady, getPlaybackState());
|
||||||
updatePlayWhenReady(
|
updatePlayWhenReady(playWhenReady, playerCommand, getPlayWhenReadyChangeReason(playerCommand));
|
||||||
playWhenReady, playerCommand, getPlayWhenReadyChangeReason(playWhenReady, playerCommand));
|
|
||||||
listeners.flushEvents();
|
listeners.flushEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2836,7 +2833,7 @@ import java.util.concurrent.TimeoutException;
|
|||||||
@PlaybackSuppressionReason
|
@PlaybackSuppressionReason
|
||||||
private int computePlaybackSuppressionReason(
|
private int computePlaybackSuppressionReason(
|
||||||
boolean playWhenReady, @AudioFocusManager.PlayerCommand int playerCommand) {
|
boolean playWhenReady, @AudioFocusManager.PlayerCommand int playerCommand) {
|
||||||
if (playWhenReady && playerCommand != AudioFocusManager.PLAYER_COMMAND_PLAY_WHEN_READY) {
|
if (playerCommand == AudioFocusManager.PLAYER_COMMAND_WAIT_FOR_CALLBACK) {
|
||||||
return Player.PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS;
|
return Player.PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS;
|
||||||
}
|
}
|
||||||
if (suppressPlaybackOnUnsuitableOutput) {
|
if (suppressPlaybackOnUnsuitableOutput) {
|
||||||
@ -3005,8 +3002,8 @@ import java.util.concurrent.TimeoutException;
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getPlayWhenReadyChangeReason(boolean playWhenReady, int playerCommand) {
|
private static int getPlayWhenReadyChangeReason(int playerCommand) {
|
||||||
return playWhenReady && playerCommand != AudioFocusManager.PLAYER_COMMAND_PLAY_WHEN_READY
|
return playerCommand == AudioFocusManager.PLAYER_COMMAND_DO_NOT_PLAY
|
||||||
? PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS
|
? PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS
|
||||||
: PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST;
|
: PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST;
|
||||||
}
|
}
|
||||||
@ -3291,7 +3288,7 @@ import java.util.concurrent.TimeoutException;
|
|||||||
public void executePlayerCommand(@AudioFocusManager.PlayerCommand int playerCommand) {
|
public void executePlayerCommand(@AudioFocusManager.PlayerCommand int playerCommand) {
|
||||||
boolean playWhenReady = getPlayWhenReady();
|
boolean playWhenReady = getPlayWhenReady();
|
||||||
updatePlayWhenReady(
|
updatePlayWhenReady(
|
||||||
playWhenReady, playerCommand, getPlayWhenReadyChangeReason(playWhenReady, playerCommand));
|
playWhenReady, playerCommand, getPlayWhenReadyChangeReason(playerCommand));
|
||||||
}
|
}
|
||||||
|
|
||||||
// AudioBecomingNoisyManager.EventListener implementation.
|
// AudioBecomingNoisyManager.EventListener implementation.
|
||||||
|
@ -4504,10 +4504,12 @@ public class ExoPlayerTest {
|
|||||||
run(player).untilPendingCommandsAreFullyHandled();
|
run(player).untilPendingCommandsAreFullyHandled();
|
||||||
player.pause();
|
player.pause();
|
||||||
boolean playWhenReady = player.getPlayWhenReady();
|
boolean playWhenReady = player.getPlayWhenReady();
|
||||||
|
@Player.PlaybackSuppressionReason int suppressionReason = player.getPlaybackSuppressionReason();
|
||||||
player.release();
|
player.release();
|
||||||
|
|
||||||
assertThat(playWhenReady).isFalse();
|
assertThat(playWhenReady).isFalse();
|
||||||
// TODO: Fix behavior and assert that suppression reason if transient audio focus loss.
|
assertThat(suppressionReason)
|
||||||
|
.isEqualTo(Player.PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS);
|
||||||
InOrder inOrder = inOrder(listener);
|
InOrder inOrder = inOrder(listener);
|
||||||
inOrder
|
inOrder
|
||||||
.verify(listener)
|
.verify(listener)
|
||||||
@ -4607,7 +4609,10 @@ public class ExoPlayerTest {
|
|||||||
.verify(listener)
|
.verify(listener)
|
||||||
.onPlayWhenReadyChanged(
|
.onPlayWhenReadyChanged(
|
||||||
/* playWhenReady= */ false, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
/* playWhenReady= */ false, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
||||||
// TODO: Fix behavior and assert that audio focus loss is reported via onPlayWhenReadyChanged.
|
inOrder
|
||||||
|
.verify(listener)
|
||||||
|
.onPlayWhenReadyChanged(
|
||||||
|
/* playWhenReady= */ false, Player.PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -4629,17 +4634,22 @@ public class ExoPlayerTest {
|
|||||||
.onAudioFocusChange(AudioManager.AUDIOFOCUS_LOSS_TRANSIENT);
|
.onAudioFocusChange(AudioManager.AUDIOFOCUS_LOSS_TRANSIENT);
|
||||||
run(player).untilPendingCommandsAreFullyHandled();
|
run(player).untilPendingCommandsAreFullyHandled();
|
||||||
boolean playWhenReady = player.getPlayWhenReady();
|
boolean playWhenReady = player.getPlayWhenReady();
|
||||||
|
@Player.PlaybackSuppressionReason int suppressionReason = player.getPlaybackSuppressionReason();
|
||||||
shadowOf(audioManager)
|
shadowOf(audioManager)
|
||||||
.getLastAudioFocusRequest()
|
.getLastAudioFocusRequest()
|
||||||
.listener
|
.listener
|
||||||
.onAudioFocusChange(AudioManager.AUDIOFOCUS_GAIN);
|
.onAudioFocusChange(AudioManager.AUDIOFOCUS_GAIN);
|
||||||
run(player).untilPendingCommandsAreFullyHandled();
|
run(player).untilPendingCommandsAreFullyHandled();
|
||||||
boolean playWhenReadyAfterGain = player.getPlayWhenReady();
|
boolean playWhenReadyAfterGain = player.getPlayWhenReady();
|
||||||
|
@Player.PlaybackSuppressionReason
|
||||||
|
int suppressionReasonAfterGain = player.getPlaybackSuppressionReason();
|
||||||
player.release();
|
player.release();
|
||||||
|
|
||||||
assertThat(playWhenReady).isFalse();
|
assertThat(playWhenReady).isFalse();
|
||||||
assertThat(playWhenReadyAfterGain).isFalse();
|
assertThat(playWhenReadyAfterGain).isFalse();
|
||||||
// TODO: Fix behavior and assert that suppression reason is transient audio focus loss.
|
assertThat(suppressionReason)
|
||||||
|
.isEqualTo(Player.PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS);
|
||||||
|
assertThat(suppressionReasonAfterGain).isEqualTo(Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||||
InOrder inOrder = inOrder(listener);
|
InOrder inOrder = inOrder(listener);
|
||||||
inOrder
|
inOrder
|
||||||
.verify(listener)
|
.verify(listener)
|
||||||
@ -4649,6 +4659,13 @@ public class ExoPlayerTest {
|
|||||||
.verify(listener)
|
.verify(listener)
|
||||||
.onPlayWhenReadyChanged(
|
.onPlayWhenReadyChanged(
|
||||||
/* playWhenReady= */ false, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
/* playWhenReady= */ false, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
||||||
|
inOrder
|
||||||
|
.verify(listener)
|
||||||
|
.onPlaybackSuppressionReasonChanged(
|
||||||
|
Player.PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS);
|
||||||
|
inOrder
|
||||||
|
.verify(listener)
|
||||||
|
.onPlaybackSuppressionReasonChanged(Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||||
verify(listener, never())
|
verify(listener, never())
|
||||||
.onPlayWhenReadyChanged(
|
.onPlayWhenReadyChanged(
|
||||||
/* playWhenReady= */ false, Player.PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS);
|
/* playWhenReady= */ false, Player.PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS);
|
||||||
@ -4679,7 +4696,6 @@ public class ExoPlayerTest {
|
|||||||
|
|
||||||
assertThat(playWhenReady).isTrue();
|
assertThat(playWhenReady).isTrue();
|
||||||
assertThat(suppressionReason).isEqualTo(Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
assertThat(suppressionReason).isEqualTo(Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||||
// TODO: Fix behavior and assert that suppression reason is transient audio focus loss.
|
|
||||||
InOrder inOrder = inOrder(listener);
|
InOrder inOrder = inOrder(listener);
|
||||||
inOrder
|
inOrder
|
||||||
.verify(listener)
|
.verify(listener)
|
||||||
@ -4689,10 +4705,17 @@ public class ExoPlayerTest {
|
|||||||
.verify(listener)
|
.verify(listener)
|
||||||
.onPlayWhenReadyChanged(
|
.onPlayWhenReadyChanged(
|
||||||
/* playWhenReady= */ false, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
/* playWhenReady= */ false, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
||||||
|
inOrder
|
||||||
|
.verify(listener)
|
||||||
|
.onPlaybackSuppressionReasonChanged(
|
||||||
|
Player.PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS);
|
||||||
inOrder
|
inOrder
|
||||||
.verify(listener)
|
.verify(listener)
|
||||||
.onPlayWhenReadyChanged(
|
.onPlayWhenReadyChanged(
|
||||||
/* playWhenReady= */ true, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
/* playWhenReady= */ true, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
||||||
|
inOrder
|
||||||
|
.verify(listener)
|
||||||
|
.onPlaybackSuppressionReasonChanged(Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||||
verify(listener, never())
|
verify(listener, never())
|
||||||
.onPlayWhenReadyChanged(
|
.onPlayWhenReadyChanged(
|
||||||
/* playWhenReady= */ false, Player.PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS);
|
/* playWhenReady= */ false, Player.PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user