diff --git a/RELEASENOTES.md b/RELEASENOTES.md index aac69e1438..5d14b6f6a1 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,6 +1,14 @@ # Release notes # -### 2.10.6 (2019-10-18) ### +### 2.10.7 (2019-11-12) ### + +* HLS: Fix detection of Dolby Atmos to match the HLS authoring specification. +* MediaSession extension: Update shuffle and repeat modes when playback state + is invalidated ([#6582](https://github.com/google/ExoPlayer/issues/6582)). +* Fix the start of audio getting truncated when transitioning to a new + item in a playlist of opus streams. + +### 2.10.6 (2019-10-17) ### * Add `Player.onPlaybackSuppressionReasonChanged` to allow listeners to detect playbacks suppressions (e.g. transient audio focus loss) directly diff --git a/constants.gradle b/constants.gradle index 2a8d0c5776..59b6b7ff42 100644 --- a/constants.gradle +++ b/constants.gradle @@ -13,8 +13,8 @@ // limitations under the License. project.ext { // ExoPlayer version and version code. - releaseVersion = '2.10.6' - releaseVersionCode = 2010006 + releaseVersion = '2.10.7' + releaseVersionCode = 2010007 minSdkVersion = 16 targetSdkVersion = 28 compileSdkVersion = 28 diff --git a/extensions/leanback/src/main/java/com/google/android/exoplayer2/ext/leanback/LeanbackPlayerAdapter.java b/extensions/leanback/src/main/java/com/google/android/exoplayer2/ext/leanback/LeanbackPlayerAdapter.java index 3f4c5d6229..15af90f38b 100644 --- a/extensions/leanback/src/main/java/com/google/android/exoplayer2/ext/leanback/LeanbackPlayerAdapter.java +++ b/extensions/leanback/src/main/java/com/google/android/exoplayer2/ext/leanback/LeanbackPlayerAdapter.java @@ -308,7 +308,11 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter implements Runnab @Override public void onVideoSizeChanged( int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { - getCallback().onVideoSizeChanged(LeanbackPlayerAdapter.this, width, height); + // There's no way to pass pixelWidthHeightRatio to leanback, so we scale the width that we + // pass to take it into account. This is necessary to ensure that leanback uses the correct + // aspect ratio when playing content with non-square pixels. + int scaledWidth = Math.round(width * pixelWidthHeightRatio); + getCallback().onVideoSizeChanged(LeanbackPlayerAdapter.this, scaledWidth, height); } @Override diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java index f42e050991..284acd8d11 100644 --- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java +++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java @@ -700,6 +700,9 @@ public final class MediaSessionConnector { /* position= */ 0, /* playbackSpeed= */ 0, /* updateTime= */ SystemClock.elapsedRealtime()); + + mediaSession.setRepeatMode(PlaybackStateCompat.REPEAT_MODE_NONE); + mediaSession.setShuffleMode(PlaybackStateCompat.SHUFFLE_MODE_NONE); mediaSession.setPlaybackState(builder.build()); return; } @@ -748,6 +751,18 @@ public final class MediaSessionConnector { sessionPlaybackSpeed, /* updateTime= */ SystemClock.elapsedRealtime()) .setExtras(extras); + + @Player.RepeatMode int repeatMode = player.getRepeatMode(); + mediaSession.setRepeatMode( + repeatMode == Player.REPEAT_MODE_ONE + ? PlaybackStateCompat.REPEAT_MODE_ONE + : repeatMode == Player.REPEAT_MODE_ALL + ? PlaybackStateCompat.REPEAT_MODE_ALL + : PlaybackStateCompat.REPEAT_MODE_NONE); + mediaSession.setShuffleMode( + player.getShuffleModeEnabled() + ? PlaybackStateCompat.SHUFFLE_MODE_ALL + : PlaybackStateCompat.SHUFFLE_MODE_NONE); mediaSession.setPlaybackState(builder.build()); } @@ -1047,21 +1062,11 @@ public final class MediaSessionConnector { @Override public void onRepeatModeChanged(@Player.RepeatMode int repeatMode) { - mediaSession.setRepeatMode( - repeatMode == Player.REPEAT_MODE_ONE - ? PlaybackStateCompat.REPEAT_MODE_ONE - : repeatMode == Player.REPEAT_MODE_ALL - ? PlaybackStateCompat.REPEAT_MODE_ALL - : PlaybackStateCompat.REPEAT_MODE_NONE); invalidateMediaSessionPlaybackState(); } @Override public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) { - mediaSession.setShuffleMode( - shuffleModeEnabled - ? PlaybackStateCompat.SHUFFLE_MODE_ALL - : PlaybackStateCompat.SHUFFLE_MODE_NONE); invalidateMediaSessionPlaybackState(); invalidateMediaSessionQueue(); } 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 adc05eb204..79d395a858 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 @@ -29,11 +29,11 @@ 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.10.6"; + public static final String VERSION = "2.10.7"; /** 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.10.6"; + public static final String VERSION_SLASHY = "ExoPlayerLib/2.10.7"; /** * The version of the library expressed as an integer, for example 1002003. @@ -43,7 +43,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 = 2010006; + public static final int VERSION_INT = 2010007; /** * 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/audio/MediaCodecAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java index f10f45ecf3..36db657956 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java @@ -434,13 +434,34 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media } else if (codecInfo.isSeamlessAdaptationSupported( oldFormat, newFormat, /* isNewFormatComplete= */ true)) { return KEEP_CODEC_RESULT_YES_WITHOUT_RECONFIGURATION; - } else if (areCodecConfigurationCompatible(oldFormat, newFormat)) { + } else if (canKeepCodecWithFlush(oldFormat, newFormat)) { return KEEP_CODEC_RESULT_YES_WITH_FLUSH; } else { return KEEP_CODEC_RESULT_NO; } } + /** + * Returns whether the codec can be flushed and reused when switching to a new format. Reuse is + * generally possible when the codec would be configured in an identical way after the format + * change (excluding {@link MediaFormat#KEY_MAX_INPUT_SIZE} and configuration that does not come + * from the {@link Format}). + * + * @param oldFormat The first format. + * @param newFormat The second format. + * @return Whether the codec can be flushed and reused when switching to a new format. + */ + protected boolean canKeepCodecWithFlush(Format oldFormat, Format newFormat) { + // Flush and reuse the codec if the audio format and initialization data matches. For Opus, we + // don't flush and reuse the codec because the decoder may discard samples after flushing, which + // would result in audio being dropped just after a stream change (see [Internal: b/143450854]). + return Util.areEqual(oldFormat.sampleMimeType, newFormat.sampleMimeType) + && oldFormat.channelCount == newFormat.channelCount + && oldFormat.sampleRate == newFormat.sampleRate + && oldFormat.initializationDataEquals(newFormat) + && !MimeTypes.AUDIO_OPUS.equals(oldFormat.sampleMimeType); + } + @Override public MediaClock getMediaClock() { return this; @@ -818,24 +839,6 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media return format.maxInputSize; } - /** - * Returns whether two {@link Format}s will cause the same codec to be configured in an identical - * way, excluding {@link MediaFormat#KEY_MAX_INPUT_SIZE} and configuration that does not come from - * the {@link Format}. - * - * @param oldFormat The first format. - * @param newFormat The second format. - * @return Whether the two formats will cause a codec to be configured in an identical way, - * excluding {@link MediaFormat#KEY_MAX_INPUT_SIZE} and configuration that does not come from - * the {@link Format}. - */ - protected boolean areCodecConfigurationCompatible(Format oldFormat, Format newFormat) { - return Util.areEqual(oldFormat.sampleMimeType, newFormat.sampleMimeType) - && oldFormat.channelCount == newFormat.channelCount - && oldFormat.sampleRate == newFormat.sampleRate - && oldFormat.initializationDataEquals(newFormat); - } - /** * Returns the framework {@link MediaFormat} that can be used to configure a {@link MediaCodec} * for decoding the given {@link Format} for playback. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/Extractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/Extractor.java index 083f31bcc3..a9151a1b7c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/Extractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/Extractor.java @@ -89,6 +89,10 @@ public interface Extractor { * {@link #RESULT_SEEK} is returned. If the extractor reached the end of the data provided by the * {@link ExtractorInput}, then {@link #RESULT_END_OF_INPUT} is returned. * + *
When this method throws an {@link IOException} or an {@link InterruptedException},
+ * extraction may continue by providing an {@link ExtractorInput} with an unchanged {@link
+ * ExtractorInput#getPosition() read position} to a subsequent call to this method.
+ *
* @param input The {@link ExtractorInput} from which data should be read.
* @param seekPosition If {@link #RESULT_SEEK} is returned, this holder is updated to hold the
* position of the required data.
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java
index c4e6ef17c4..58bd59a448 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java
@@ -348,9 +348,7 @@ import java.util.List;
}
long durationUs = Util.scaleLargeTimestamp(duration, C.MICROS_PER_SECOND, track.timescale);
- if (track.editListDurations == null || gaplessInfoHolder.hasGaplessInfo()) {
- // There is no edit list, or we are ignoring it as we already have gapless metadata to apply.
- // This implementation does not support applying both gapless metadata and an edit list.
+ if (track.editListDurations == null) {
Util.scaleLargeTimestampsInPlace(timestamps, C.MICROS_PER_SECOND, track.timescale);
return new TrackSampleTable(
track, offsets, sizes, maximumSize, timestamps, flags, durationUs);
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/FlacReader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/FlacReader.java
index 4efd5c5e11..e1218b5572 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/FlacReader.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/FlacReader.java
@@ -78,17 +78,17 @@ import java.util.List;
List
- * Must not be called if the device SDK version is less than 21.
+ *
+ * Must not be called if the device SDK version is less than 21.
*
* @param width Width in pixels.
* @param height Height in pixels.
- * @param frameRate Optional frame rate in frames per second. Ignored if set to
- * {@link Format#NO_VALUE} or any value less than or equal to 0.
+ * @param frameRate Optional frame rate in frames per second. Ignored if set to {@link
+ * Format#NO_VALUE} or any value less than or equal to 0.
* @return Whether the decoder supports video with the given width, height and frame rate.
*/
@TargetApi(21)
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/Cue.java b/library/core/src/main/java/com/google/android/exoplayer2/text/Cue.java
index 3f6ff44248..54e7c869e1 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/text/Cue.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/text/Cue.java
@@ -32,7 +32,8 @@ public class Cue {
public static final Cue EMPTY = new Cue("");
/** An unset position or width. */
- public static final float DIMEN_UNSET = Float.MIN_VALUE;
+ // Note: We deliberately don't use Float.MIN_VALUE because it's positive & very close to zero.
+ public static final float DIMEN_UNSET = -Float.MAX_VALUE;
/**
* The type of anchor, which may be unset. One of {@link #TYPE_UNSET}, {@link #ANCHOR_TYPE_START},
diff --git a/library/core/src/test/assets/ogg/bear_flac.ogg.0.dump b/library/core/src/test/assets/ogg/bear_flac.ogg.0.dump
index dbe97c02bd..5b8d893f1a 100644
--- a/library/core/src/test/assets/ogg/bear_flac.ogg.0.dump
+++ b/library/core/src/test/assets/ogg/bear_flac.ogg.0.dump
@@ -5,11 +5,11 @@ seekMap:
numberOfTracks = 1
track 0:
format:
- bitrate = -1
+ bitrate = 768000
id = null
containerMimeType = null
sampleMimeType = audio/flac
- maxInputSize = 768000
+ maxInputSize = -1
width = -1
height = -1
frameRate = -1.0
diff --git a/library/core/src/test/assets/ogg/bear_flac.ogg.1.dump b/library/core/src/test/assets/ogg/bear_flac.ogg.1.dump
index d1246a3e64..fff76c5b05 100644
--- a/library/core/src/test/assets/ogg/bear_flac.ogg.1.dump
+++ b/library/core/src/test/assets/ogg/bear_flac.ogg.1.dump
@@ -5,11 +5,11 @@ seekMap:
numberOfTracks = 1
track 0:
format:
- bitrate = -1
+ bitrate = 768000
id = null
containerMimeType = null
sampleMimeType = audio/flac
- maxInputSize = 768000
+ maxInputSize = -1
width = -1
height = -1
frameRate = -1.0
diff --git a/library/core/src/test/assets/ogg/bear_flac.ogg.2.dump b/library/core/src/test/assets/ogg/bear_flac.ogg.2.dump
index ec0336309a..b4d3534161 100644
--- a/library/core/src/test/assets/ogg/bear_flac.ogg.2.dump
+++ b/library/core/src/test/assets/ogg/bear_flac.ogg.2.dump
@@ -5,11 +5,11 @@ seekMap:
numberOfTracks = 1
track 0:
format:
- bitrate = -1
+ bitrate = 768000
id = null
containerMimeType = null
sampleMimeType = audio/flac
- maxInputSize = 768000
+ maxInputSize = -1
width = -1
height = -1
frameRate = -1.0
diff --git a/library/core/src/test/assets/ogg/bear_flac.ogg.3.dump b/library/core/src/test/assets/ogg/bear_flac.ogg.3.dump
index 1e3254a9fc..27c29cba58 100644
--- a/library/core/src/test/assets/ogg/bear_flac.ogg.3.dump
+++ b/library/core/src/test/assets/ogg/bear_flac.ogg.3.dump
@@ -5,11 +5,11 @@ seekMap:
numberOfTracks = 1
track 0:
format:
- bitrate = -1
+ bitrate = 768000
id = null
containerMimeType = null
sampleMimeType = audio/flac
- maxInputSize = 768000
+ maxInputSize = -1
width = -1
height = -1
frameRate = -1.0
diff --git a/library/core/src/test/assets/ogg/bear_flac.ogg.unklen.dump b/library/core/src/test/assets/ogg/bear_flac.ogg.unklen.dump
index dbe97c02bd..5b8d893f1a 100644
--- a/library/core/src/test/assets/ogg/bear_flac.ogg.unklen.dump
+++ b/library/core/src/test/assets/ogg/bear_flac.ogg.unklen.dump
@@ -5,11 +5,11 @@ seekMap:
numberOfTracks = 1
track 0:
format:
- bitrate = -1
+ bitrate = 768000
id = null
containerMimeType = null
sampleMimeType = audio/flac
- maxInputSize = 768000
+ maxInputSize = -1
width = -1
height = -1
frameRate = -1.0
diff --git a/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.0.dump b/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.0.dump
index cce7bf2450..2ecdc9784c 100644
--- a/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.0.dump
+++ b/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.0.dump
@@ -5,11 +5,11 @@ seekMap:
numberOfTracks = 1
track 0:
format:
- bitrate = -1
+ bitrate = 768000
id = null
containerMimeType = null
sampleMimeType = audio/flac
- maxInputSize = 768000
+ maxInputSize = -1
width = -1
height = -1
frameRate = -1.0
diff --git a/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.1.dump b/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.1.dump
index ac36a48412..0ed2a86b9e 100644
--- a/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.1.dump
+++ b/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.1.dump
@@ -5,11 +5,11 @@ seekMap:
numberOfTracks = 1
track 0:
format:
- bitrate = -1
+ bitrate = 768000
id = null
containerMimeType = null
sampleMimeType = audio/flac
- maxInputSize = 768000
+ maxInputSize = -1
width = -1
height = -1
frameRate = -1.0
diff --git a/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.2.dump b/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.2.dump
index dae0d878fa..229e90584e 100644
--- a/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.2.dump
+++ b/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.2.dump
@@ -5,11 +5,11 @@ seekMap:
numberOfTracks = 1
track 0:
format:
- bitrate = -1
+ bitrate = 768000
id = null
containerMimeType = null
sampleMimeType = audio/flac
- maxInputSize = 768000
+ maxInputSize = -1
width = -1
height = -1
frameRate = -1.0
diff --git a/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.3.dump b/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.3.dump
index c9570ab58e..89c6d178ff 100644
--- a/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.3.dump
+++ b/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.3.dump
@@ -5,11 +5,11 @@ seekMap:
numberOfTracks = 1
track 0:
format:
- bitrate = -1
+ bitrate = 768000
id = null
containerMimeType = null
sampleMimeType = audio/flac
- maxInputSize = 768000
+ maxInputSize = -1
width = -1
height = -1
frameRate = -1.0
diff --git a/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.unklen.dump b/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.unklen.dump
index 7a3e7ef5ac..7a4ba81f23 100644
--- a/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.unklen.dump
+++ b/library/core/src/test/assets/ogg/bear_flac_noseektable.ogg.unklen.dump
@@ -5,11 +5,11 @@ seekMap:
numberOfTracks = 1
track 0:
format:
- bitrate = -1
+ bitrate = 768000
id = null
containerMimeType = null
sampleMimeType = audio/flac
- maxInputSize = 768000
+ maxInputSize = -1
width = -1
height = -1
frameRate = -1.0
diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java
index 030520f8cb..7ccbaf5d59 100644
--- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java
+++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java
@@ -445,7 +445,15 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser