diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 4101caad47..8ad866395e 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,5 +1,12 @@ # Release notes # +### r2.5.1 ### + +* Fix an issue that could cause the reported playback position to stop advancing + in some cases. +* Fix an issue where a Surface could be released whilst still in use by the + player. + ### r2.5.0 ### * IMA extension: Wraps the Google Interactive Media Ads (IMA) SDK to provide an diff --git a/constants.gradle b/constants.gradle index 7d126ccd89..b7cc8b6906 100644 --- a/constants.gradle +++ b/constants.gradle @@ -24,7 +24,7 @@ project.ext { supportLibraryVersion = '25.4.0' dexmakerVersion = '1.2' mockitoVersion = '1.9.5' - releaseVersion = 'r2.5.0' + releaseVersion = 'r2.5.1' modulePrefix = ':' if (gradle.ext.has('exoplayerModulePrefix')) { modulePrefix += gradle.ext.exoplayerModulePrefix diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml index 0e04d9a435..1f66822dc7 100644 --- a/demo/src/main/AndroidManifest.xml +++ b/demo/src/main/AndroidManifest.xml @@ -16,8 +16,8 @@ + android:versionCode="2501" + android:versionName="2.5.1"> diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index cb04501fc0..a789dbc1b2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -975,11 +975,10 @@ import java.io.IOException; mediaPeriodInfoSequence.setTimeline(timeline); Object manifest = timelineAndManifest.second; - int processedInitialSeekCount = 0; if (oldTimeline == null) { if (pendingInitialSeekCount > 0) { Pair periodPosition = resolveSeekPosition(pendingSeekPosition); - processedInitialSeekCount = pendingInitialSeekCount; + int processedInitialSeekCount = pendingInitialSeekCount; pendingInitialSeekCount = 0; pendingSeekPosition = null; if (periodPosition == null) { @@ -996,7 +995,7 @@ import java.io.IOException; } } else if (playbackInfo.startPositionUs == C.TIME_UNSET) { if (timeline.isEmpty()) { - handleSourceInfoRefreshEndedPlayback(manifest, processedInitialSeekCount); + handleSourceInfoRefreshEndedPlayback(manifest); } else { Pair defaultPosition = getPeriodPosition(0, C.TIME_UNSET); int periodIndex = defaultPosition.first; @@ -1005,8 +1004,10 @@ import java.io.IOException; startPositionUs); playbackInfo = new PlaybackInfo(periodId, periodId.isAd() ? 0 : startPositionUs, startPositionUs); - notifySourceInfoRefresh(manifest, processedInitialSeekCount); + notifySourceInfoRefresh(manifest); } + } else { + notifySourceInfoRefresh(manifest); } return; } @@ -1015,7 +1016,7 @@ import java.io.IOException; MediaPeriodHolder periodHolder = playingPeriodHolder != null ? playingPeriodHolder : loadingPeriodHolder; if (periodHolder == null && playingPeriodIndex >= oldTimeline.getPeriodCount()) { - notifySourceInfoRefresh(manifest, processedInitialSeekCount); + notifySourceInfoRefresh(manifest); return; } Object playingPeriodUid = periodHolder == null @@ -1027,7 +1028,7 @@ import java.io.IOException; int newPeriodIndex = resolveSubsequentPeriod(playingPeriodIndex, oldTimeline, timeline); if (newPeriodIndex == C.INDEX_UNSET) { // We failed to resolve a suitable restart position. - handleSourceInfoRefreshEndedPlayback(manifest, processedInitialSeekCount); + handleSourceInfoRefreshEndedPlayback(manifest); return; } // We resolved a subsequent period. Seek to the default position in the corresponding window. @@ -1055,7 +1056,7 @@ import java.io.IOException; MediaPeriodId periodId = new MediaPeriodId(newPeriodIndex); newPositionUs = seekToPeriodPosition(periodId, newPositionUs); playbackInfo = new PlaybackInfo(periodId, newPositionUs); - notifySourceInfoRefresh(manifest, processedInitialSeekCount); + notifySourceInfoRefresh(manifest); return; } @@ -1072,14 +1073,14 @@ import java.io.IOException; long newPositionUs = seekToPeriodPosition(periodId, playbackInfo.contentPositionUs); long contentPositionUs = periodId.isAd() ? playbackInfo.contentPositionUs : C.TIME_UNSET; playbackInfo = new PlaybackInfo(periodId, newPositionUs, contentPositionUs); - notifySourceInfoRefresh(manifest, processedInitialSeekCount); + notifySourceInfoRefresh(manifest); return; } } if (periodHolder == null) { // We don't have any period holders, so we're done. - notifySourceInfoRefresh(manifest, processedInitialSeekCount); + notifySourceInfoRefresh(manifest); return; } @@ -1117,7 +1118,7 @@ import java.io.IOException; } } - notifySourceInfoRefresh(manifest, processedInitialSeekCount); + notifySourceInfoRefresh(manifest); } private MediaPeriodHolder updatePeriodInfo(MediaPeriodHolder periodHolder, int periodIndex) { @@ -1131,6 +1132,10 @@ import java.io.IOException; } } + private void handleSourceInfoRefreshEndedPlayback(Object manifest) { + handleSourceInfoRefreshEndedPlayback(manifest, 0); + } + private void handleSourceInfoRefreshEndedPlayback(Object manifest, int processedInitialSeekCount) { // Set the playback position to (0,0) for notifying the eventHandler. @@ -1143,6 +1148,10 @@ import java.io.IOException; resetInternal(false); } + private void notifySourceInfoRefresh(Object manifest) { + notifySourceInfoRefresh(manifest, 0); + } + private void notifySourceInfoRefresh(Object manifest, int processedInitialSeekCount) { eventHandler.obtainMessage(MSG_SOURCE_INFO_REFRESHED, new SourceInfo(timeline, manifest, playbackInfo, processedInitialSeekCount)).sendToTarget(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java index fd5ead5c85..33f992964a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java @@ -31,13 +31,13 @@ public final class ExoPlayerLibraryInfo { * The version of the library expressed as a string, for example "1.2.3". */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa. - public static final String VERSION = "2.5.0"; + public static final String VERSION = "2.5.1"; /** * The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final String VERSION_SLASHY = "ExoPlayerLib/2.5.0"; + public static final String VERSION_SLASHY = "ExoPlayerLib/2.5.1"; /** * The version of the library expressed as an integer, for example 1002003. @@ -47,7 +47,7 @@ public final class ExoPlayerLibraryInfo { * integer version 123045006 (123-045-006). */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final int VERSION_INT = 2005000; + public static final int VERSION_INT = 2005001; /** * Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 08e178878b..3a3768bcc2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -749,12 +749,12 @@ public class SimpleExoPlayer implements ExoPlayer { } } if (this.surface != null && this.surface != surface) { - // If we created this surface, we are responsible for releasing it. + // We're replacing a surface. Block to ensure that it's not accessed after the method returns. + player.blockingSendMessages(messages); + // If we created the previous surface, we are responsible for releasing it. if (this.ownsSurface) { this.surface.release(); } - // We're replacing a surface. Block to ensure that it's not accessed after the method returns. - player.blockingSendMessages(messages); } else { player.sendMessages(messages); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java index 32c4eb6c73..8be6bf028f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java @@ -48,7 +48,9 @@ public final class ClippingMediaSource implements MediaSource, MediaSource.Liste * start providing samples, in microseconds. * @param endPositionUs The end position within {@code mediaSource}'s timeline at which to stop * providing samples, in microseconds. Specify {@link C#TIME_END_OF_SOURCE} to provide samples - * from the specified start point up to the end of the source. + * from the specified start point up to the end of the source. Specifying a position that + * exceeds the {@code mediaSource}'s duration will also result in the end of the source not + * being clipped. */ public ClippingMediaSource(MediaSource mediaSource, long startPositionUs, long endPositionUs) { this(mediaSource, startPositionUs, endPositionUs, true); @@ -66,7 +68,9 @@ public final class ClippingMediaSource implements MediaSource, MediaSource.Liste * start providing samples, in microseconds. * @param endPositionUs The end position within {@code mediaSource}'s timeline at which to stop * providing samples, in microseconds. Specify {@link C#TIME_END_OF_SOURCE} to provide samples - * from the specified start point up to the end of the source. + * from the specified start point up to the end of the source. Specifying a position that + * exceeds the {@code mediaSource}'s duration will also result in the end of the source not + * being clipped. * @param enableInitialDiscontinuity Whether the initial discontinuity should be enabled. */ public ClippingMediaSource(MediaSource mediaSource, long startPositionUs, long endPositionUs, @@ -149,8 +153,10 @@ public final class ClippingMediaSource implements MediaSource, MediaSource.Liste Assertions.checkArgument(!window.isDynamic); long resolvedEndUs = endUs == C.TIME_END_OF_SOURCE ? window.durationUs : endUs; if (window.durationUs != C.TIME_UNSET) { + if (resolvedEndUs > window.durationUs) { + resolvedEndUs = window.durationUs; + } Assertions.checkArgument(startUs == 0 || window.isSeekable); - Assertions.checkArgument(resolvedEndUs <= window.durationUs); Assertions.checkArgument(startUs <= resolvedEndUs); } Period period = timeline.getPeriod(0, new Period());