From d67b70340e9d584c5fb2fdd0a3af8c8b5539f1be Mon Sep 17 00:00:00 2001 From: sungsoo Date: Fri, 20 Nov 2020 06:06:55 +0000 Subject: [PATCH] Refactor ComponentListener of PlayerWrapper PiperOrigin-RevId: 343432873 --- RELEASENOTES.md | 3 + .../media2/SessionPlayerConnectorTest.java | 1 - .../exoplayer2/ext/media2/PlayerWrapper.java | 196 ++++++++---------- 3 files changed, 88 insertions(+), 112 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index fdc3db7f3b..a1266fa54d 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -80,6 +80,9 @@ that lie outside the length of the cue text. * Metadata retriever: * Parse Google Photos HEIC motion photos metadata. +* Media2 extention: + * Notify onBufferingEnded when the state of origin player becomes + STATE_IDLE or STATE_ENDED. ### 2.12.1 (2020-10-23) ### diff --git a/extensions/media2/src/androidTest/java/com/google/android/exoplayer2/ext/media2/SessionPlayerConnectorTest.java b/extensions/media2/src/androidTest/java/com/google/android/exoplayer2/ext/media2/SessionPlayerConnectorTest.java index b80cbe5a5f..cd831fcf1f 100644 --- a/extensions/media2/src/androidTest/java/com/google/android/exoplayer2/ext/media2/SessionPlayerConnectorTest.java +++ b/extensions/media2/src/androidTest/java/com/google/android/exoplayer2/ext/media2/SessionPlayerConnectorTest.java @@ -826,7 +826,6 @@ public class SessionPlayerConnectorTest { } } }); - sessionPlayerConnector.setPlaylist(playlistToSessionPlayer, /* metadata= */ null); InstrumentationRegistry.getInstrumentation() .runOnMainSync(() -> playerTestRule.getSimpleExoPlayer().setMediaItems(exoMediaItems)); assertThat(onPlaylistChangedLatch.await(PLAYLIST_CHANGE_WAIT_TIME_MS, MILLISECONDS)).isTrue(); diff --git a/extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/PlayerWrapper.java b/extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/PlayerWrapper.java index 376885fd6a..1cf322c792 100644 --- a/extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/PlayerWrapper.java +++ b/extensions/media2/src/main/java/com/google/android/exoplayer2/ext/media2/PlayerWrapper.java @@ -65,10 +65,10 @@ import java.util.List; /** Called when a seek request has completed. */ void onSeekCompleted(); - /** Called when the player rebuffers. */ + /** Called when the player starts buffering. */ void onBufferingStarted(androidx.media2.common.MediaItem media2MediaItem); - /** Called when the player becomes ready again after rebuffering. */ + /** Called when the player becomes ready again after buffering started. */ void onBufferingEnded( androidx.media2.common.MediaItem media2MediaItem, int bufferingPercentage); @@ -120,8 +120,9 @@ import java.util.List; private final List exoPlayerPlaylist; private ControlDispatcher controlDispatcher; + private int sessionPlayerState; private boolean prepared; - private boolean rebuffering; + @Nullable private androidx.media2.common.MediaItem bufferingItem; private int currentWindowIndex; private boolean ignoreTimelineUpdates; @@ -154,11 +155,14 @@ import java.util.List; media2Playlist = new ArrayList<>(); exoPlayerPlaylist = new ArrayList<>(); currentWindowIndex = C.INDEX_UNSET; - - prepared = player.getPlaybackState() != Player.STATE_IDLE; - rebuffering = player.getPlaybackState() == Player.STATE_BUFFERING; - updatePlaylist(player.getCurrentTimeline()); + + sessionPlayerState = evaluateSessionPlayerState(); + @Player.State int playbackState = player.getPlaybackState(); + prepared = playbackState != Player.STATE_IDLE; + if (playbackState == Player.STATE_BUFFERING) { + bufferingItem = getCurrentMediaItem(); + } } public void setControlDispatcher(ControlDispatcher controlDispatcher) { @@ -360,7 +364,7 @@ import java.util.List; } /* @SessionPlayer.PlayerState */ - private int getState() { + private int evaluateSessionPlayerState() { if (hasError()) { return SessionPlayer.PLAYER_STATE_ERROR; } @@ -381,6 +385,63 @@ import java.util.List; } } + private void updateSessionPlayerState() { + int newState = evaluateSessionPlayerState(); + if (sessionPlayerState != newState) { + sessionPlayerState = newState; + listener.onPlayerStateChanged(newState); + if (newState == SessionPlayer.PLAYER_STATE_ERROR) { + listener.onError(getCurrentMediaItem()); + } + } + } + + private void updateBufferingState(boolean isBuffering) { + if (isBuffering) { + androidx.media2.common.MediaItem curMediaItem = getCurrentMediaItem(); + if (prepared && (bufferingItem == null || !bufferingItem.equals(curMediaItem))) { + bufferingItem = getCurrentMediaItem(); + listener.onBufferingStarted(Assertions.checkNotNull(bufferingItem)); + } + } else if (bufferingItem != null) { + listener.onBufferingEnded(bufferingItem, player.getBufferedPercentage()); + bufferingItem = null; + } + } + + private void handlePlayerStateChanged() { + updateSessionPlayerState(); + + int playbackState = player.getPlaybackState(); + handler.removeCallbacks(pollBufferRunnable); + + switch (playbackState) { + case Player.STATE_IDLE: + prepared = false; + updateBufferingState(/* isBuffering= */ false); + break; + case Player.STATE_BUFFERING: + updateBufferingState(/* isBuffering= */ true); + postOrRun(handler, pollBufferRunnable); + break; + case Player.STATE_READY: + if (!prepared) { + prepared = true; + handlePositionDiscontinuity(Player.DISCONTINUITY_REASON_PERIOD_TRANSITION); + listener.onPrepared( + Assertions.checkNotNull(getCurrentMediaItem()), player.getBufferedPercentage()); + } + updateBufferingState(/* isBuffering= */ false); + postOrRun(handler, pollBufferRunnable); + break; + case Player.STATE_ENDED: + listener.onPlaybackEnded(); + player.setPlayWhenReady(false); + updateBufferingState(/* isBuffering= */ false); + break; + } + } + public void setAudioAttributes(AudioAttributesCompat audioAttributes) { Player.AudioComponent audioComponent = Assertions.checkStateNotNull(player.getAudioComponent()); audioComponent.setAudioAttributes( @@ -407,7 +468,7 @@ import java.util.List; public void reset() { controlDispatcher.dispatchStop(player, /* reset= */ true); prepared = false; - rebuffering = false; + bufferingItem = null; } public void close() { @@ -446,35 +507,6 @@ import java.util.List; return player.getPlayerError() != null; } - private void handlePlayWhenReadyChanged() { - listener.onPlayerStateChanged(getState()); - } - - private void handlePlayerStateChanged(@Player.State int state) { - if (state == Player.STATE_READY || state == Player.STATE_BUFFERING) { - postOrRun(handler, pollBufferRunnable); - } else { - handler.removeCallbacks(pollBufferRunnable); - } - - switch (state) { - case Player.STATE_BUFFERING: - maybeNotifyBufferingEvents(); - break; - case Player.STATE_READY: - maybeNotifyReadyEvents(); - break; - case Player.STATE_ENDED: - maybeNotifyEndedEvents(); - break; - case Player.STATE_IDLE: - // Do nothing. - break; - default: - throw new IllegalStateException(); - } - } - private void handlePositionDiscontinuity(@Player.DiscontinuityReason int reason) { int currentWindowIndex = getCurrentMediaItemIndex(); if (this.currentWindowIndex != currentWindowIndex) { @@ -487,34 +519,6 @@ import java.util.List; } } - private void handlePlayerError() { - listener.onPlayerStateChanged(SessionPlayer.PLAYER_STATE_ERROR); - listener.onError(getCurrentMediaItem()); - } - - private void handleRepeatModeChanged(@Player.RepeatMode int repeatMode) { - listener.onRepeatModeChanged(Utils.getRepeatMode(repeatMode)); - } - - private void handleShuffleMode(boolean shuffleModeEnabled) { - listener.onShuffleModeChanged(Utils.getShuffleMode(shuffleModeEnabled)); - } - - private void handlePlaybackParametersChanged(PlaybackParameters playbackParameters) { - listener.onPlaybackSpeedChanged(playbackParameters.speed); - } - - private void handleTimelineChanged(Timeline timeline) { - if (ignoreTimelineUpdates) { - return; - } - if (!isExoPlayerMediaItemsChanged(timeline)) { - return; - } - updatePlaylist(timeline); - listener.onPlaylistChanged(); - } - // Check whether Timeline is changed by media item changes or not private boolean isExoPlayerMediaItemsChanged(Timeline timeline) { if (exoPlayerPlaylist.size() != timeline.getWindowCount()) { @@ -554,10 +558,6 @@ import java.util.List; } } - private void handleAudioAttributesChanged(AudioAttributes audioAttributes) { - listener.onAudioAttributesChanged(Utils.getAudioAttributesCompat(audioAttributes)); - } - private void updateBufferingAndScheduleNextPollBuffer() { androidx.media2.common.MediaItem media2MediaItem = Assertions.checkNotNull(getCurrentMediaItem()); @@ -566,39 +566,6 @@ import java.util.List; handler.postDelayed(pollBufferRunnable, POLL_BUFFER_INTERVAL_MS); } - private void maybeNotifyBufferingEvents() { - androidx.media2.common.MediaItem media2MediaItem = - Assertions.checkNotNull(getCurrentMediaItem()); - if (prepared && !rebuffering) { - rebuffering = true; - listener.onBufferingStarted(media2MediaItem); - } - } - - private void maybeNotifyReadyEvents() { - androidx.media2.common.MediaItem media2MediaItem = - Assertions.checkNotNull(getCurrentMediaItem()); - boolean prepareComplete = !prepared; - if (prepareComplete) { - prepared = true; - handlePositionDiscontinuity(Player.DISCONTINUITY_REASON_PERIOD_TRANSITION); - listener.onPlayerStateChanged(SessionPlayer.PLAYER_STATE_PAUSED); - listener.onPrepared(media2MediaItem, player.getBufferedPercentage()); - } - if (rebuffering) { - rebuffering = false; - listener.onBufferingEnded(media2MediaItem, player.getBufferedPercentage()); - } - } - - private void maybeNotifyEndedEvents() { - if (player.getPlayWhenReady()) { - listener.onPlayerStateChanged(SessionPlayer.PLAYER_STATE_PAUSED); - listener.onPlaybackEnded(); - player.setPlayWhenReady(false); - } - } - private void releaseMediaItem(androidx.media2.common.MediaItem media2MediaItem) { try { if (media2MediaItem instanceof CallbackMediaItem) { @@ -615,12 +582,12 @@ import java.util.List; @Override public void onPlayWhenReadyChanged(boolean playWhenReady, int reason) { - handlePlayWhenReadyChanged(); + updateSessionPlayerState(); } @Override public void onPlaybackStateChanged(@Player.State int state) { - handlePlayerStateChanged(state); + handlePlayerStateChanged(); } @Override @@ -630,34 +597,41 @@ import java.util.List; @Override public void onPlayerError(ExoPlaybackException error) { - handlePlayerError(); + updateSessionPlayerState(); } @Override public void onRepeatModeChanged(@Player.RepeatMode int repeatMode) { - handleRepeatModeChanged(repeatMode); + listener.onRepeatModeChanged(Utils.getRepeatMode(repeatMode)); } @Override public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) { - handleShuffleMode(shuffleModeEnabled); + listener.onShuffleModeChanged(Utils.getShuffleMode(shuffleModeEnabled)); } @Override public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) { - handlePlaybackParametersChanged(playbackParameters); + listener.onPlaybackSpeedChanged(playbackParameters.speed); } @Override public void onTimelineChanged(Timeline timeline, int reason) { - handleTimelineChanged(timeline); + if (ignoreTimelineUpdates) { + return; + } + if (!isExoPlayerMediaItemsChanged(timeline)) { + return; + } + updatePlaylist(timeline); + listener.onPlaylistChanged(); } // AudioListener implementation. @Override public void onAudioAttributesChanged(AudioAttributes audioAttributes) { - handleAudioAttributesChanged(audioAttributes); + listener.onAudioAttributesChanged(Utils.getAudioAttributesCompat(audioAttributes)); } }