The extractor tracks are inspected to infer a "primary" track type. If a video track is
@@ -1518,14 +1519,14 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
}
/**
- * Derives a track sample format from the corresponding format in the master playlist, and a
+ * Derives a track sample format from the corresponding format in the multivariant playlist, and a
* sample format that may have been obtained from a chunk belonging to a different track in the
* same track group.
*
* Note: Since the sample format may have been obtained from a chunk belonging to a different
* track, it should not be used as a source for data that may vary between tracks.
*
- * @param playlistFormat The format information obtained from the master playlist.
+ * @param playlistFormat The format information obtained from the multivariant playlist.
* @param sampleFormat The format information obtained from samples within a chunk. The chunk may
* belong to a different track in the same track group.
* @param propagateBitrates Whether the bitrates from the playlist format should be included in
diff --git a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/offline/HlsDownloader.java b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/offline/HlsDownloader.java
index f1916a12a0..8f8b08bcbc 100644
--- a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/offline/HlsDownloader.java
+++ b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/offline/HlsDownloader.java
@@ -23,8 +23,8 @@ import androidx.media3.common.util.UriUtil;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.DataSpec;
import androidx.media3.datasource.cache.CacheDataSource;
-import androidx.media3.exoplayer.hls.playlist.HlsMasterPlaylist;
import androidx.media3.exoplayer.hls.playlist.HlsMediaPlaylist;
+import androidx.media3.exoplayer.hls.playlist.HlsMultivariantPlaylist;
import androidx.media3.exoplayer.hls.playlist.HlsPlaylist;
import androidx.media3.exoplayer.hls.playlist.HlsPlaylistParser;
import androidx.media3.exoplayer.offline.SegmentDownloader;
@@ -46,14 +46,14 @@ import java.util.concurrent.Executor;
* new CacheDataSource.Factory()
* .setCache(cache)
* .setUpstreamDataSourceFactory(new DefaultHttpDataSource.Factory());
- * // Create a downloader for the first variant in a master playlist.
+ * // Create a downloader for the first variant in a multivariant playlist.
* HlsDownloader hlsDownloader =
* new HlsDownloader(
* new MediaItem.Builder()
* .setUri(playlistUri)
* .setStreamKeys(
* Collections.singletonList(
- * new StreamKey(HlsMasterPlaylist.GROUP_INDEX_VARIANT, 0)))
+ * new StreamKey(HlsMultivariantPlaylist.GROUP_INDEX_VARIANT, 0)))
* .build(),
* Collections.singletonList();
* // Perform the download.
@@ -115,9 +115,9 @@ public final class HlsDownloader extends SegmentDownloader {
protected List getSegments(DataSource dataSource, HlsPlaylist playlist, boolean removing)
throws IOException, InterruptedException {
ArrayList mediaPlaylistDataSpecs = new ArrayList<>();
- if (playlist instanceof HlsMasterPlaylist) {
- HlsMasterPlaylist masterPlaylist = (HlsMasterPlaylist) playlist;
- addMediaPlaylistDataSpecs(masterPlaylist.mediaPlaylistUrls, mediaPlaylistDataSpecs);
+ if (playlist instanceof HlsMultivariantPlaylist) {
+ HlsMultivariantPlaylist multivariantPlaylist = (HlsMultivariantPlaylist) playlist;
+ addMediaPlaylistDataSpecs(multivariantPlaylist.mediaPlaylistUrls, mediaPlaylistDataSpecs);
} else {
mediaPlaylistDataSpecs.add(
SegmentDownloader.getCompressibleDataSpec(Uri.parse(playlist.baseUri)));
diff --git a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/DefaultHlsPlaylistParserFactory.java b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/DefaultHlsPlaylistParserFactory.java
index 877bde616d..7d7e0bb05b 100644
--- a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/DefaultHlsPlaylistParserFactory.java
+++ b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/DefaultHlsPlaylistParserFactory.java
@@ -30,7 +30,8 @@ public final class DefaultHlsPlaylistParserFactory implements HlsPlaylistParserF
@Override
public ParsingLoadable.Parser createPlaylistParser(
- HlsMasterPlaylist masterPlaylist, @Nullable HlsMediaPlaylist previousMediaPlaylist) {
- return new HlsPlaylistParser(masterPlaylist, previousMediaPlaylist);
+ HlsMultivariantPlaylist multivariantPlaylist,
+ @Nullable HlsMediaPlaylist previousMediaPlaylist) {
+ return new HlsPlaylistParser(multivariantPlaylist, previousMediaPlaylist);
}
}
diff --git a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/DefaultHlsPlaylistTracker.java b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/DefaultHlsPlaylistTracker.java
index 6ea60a3a6c..b8e9db0aa8 100644
--- a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/DefaultHlsPlaylistTracker.java
+++ b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/DefaultHlsPlaylistTracker.java
@@ -31,10 +31,10 @@ import androidx.media3.common.util.Util;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.HttpDataSource;
import androidx.media3.exoplayer.hls.HlsDataSourceFactory;
-import androidx.media3.exoplayer.hls.playlist.HlsMasterPlaylist.Variant;
import androidx.media3.exoplayer.hls.playlist.HlsMediaPlaylist.Part;
import androidx.media3.exoplayer.hls.playlist.HlsMediaPlaylist.RenditionReport;
import androidx.media3.exoplayer.hls.playlist.HlsMediaPlaylist.Segment;
+import androidx.media3.exoplayer.hls.playlist.HlsMultivariantPlaylist.Variant;
import androidx.media3.exoplayer.source.LoadEventInfo;
import androidx.media3.exoplayer.source.MediaLoadData;
import androidx.media3.exoplayer.source.MediaSourceEventListener.EventDispatcher;
@@ -74,7 +74,7 @@ public final class DefaultHlsPlaylistTracker
@Nullable private Loader initialPlaylistLoader;
@Nullable private Handler playlistRefreshHandler;
@Nullable private PrimaryPlaylistListener primaryPlaylistListener;
- @Nullable private HlsMasterPlaylist masterPlaylist;
+ @Nullable private HlsMultivariantPlaylist multivariantPlaylist;
@Nullable private Uri primaryMediaPlaylistUrl;
@Nullable private HlsMediaPlaylist primaryMediaPlaylistSnapshot;
private boolean isLive;
@@ -133,30 +133,33 @@ public final class DefaultHlsPlaylistTracker
this.playlistRefreshHandler = Util.createHandlerForCurrentLooper();
this.eventDispatcher = eventDispatcher;
this.primaryPlaylistListener = primaryPlaylistListener;
- ParsingLoadable masterPlaylistLoadable =
+ ParsingLoadable multivariantPlaylistLoadable =
new ParsingLoadable<>(
dataSourceFactory.createDataSource(C.DATA_TYPE_MANIFEST),
initialPlaylistUri,
C.DATA_TYPE_MANIFEST,
playlistParserFactory.createPlaylistParser());
Assertions.checkState(initialPlaylistLoader == null);
- initialPlaylistLoader = new Loader("DefaultHlsPlaylistTracker:MasterPlaylist");
+ initialPlaylistLoader = new Loader("DefaultHlsPlaylistTracker:MultivariantPlaylist");
long elapsedRealtime =
initialPlaylistLoader.startLoading(
- masterPlaylistLoadable,
+ multivariantPlaylistLoadable,
this,
- loadErrorHandlingPolicy.getMinimumLoadableRetryCount(masterPlaylistLoadable.type));
+ loadErrorHandlingPolicy.getMinimumLoadableRetryCount(
+ multivariantPlaylistLoadable.type));
eventDispatcher.loadStarted(
new LoadEventInfo(
- masterPlaylistLoadable.loadTaskId, masterPlaylistLoadable.dataSpec, elapsedRealtime),
- masterPlaylistLoadable.type);
+ multivariantPlaylistLoadable.loadTaskId,
+ multivariantPlaylistLoadable.dataSpec,
+ elapsedRealtime),
+ multivariantPlaylistLoadable.type);
}
@Override
public void stop() {
primaryMediaPlaylistUrl = null;
primaryMediaPlaylistSnapshot = null;
- masterPlaylist = null;
+ multivariantPlaylist = null;
initialStartTimeUs = C.TIME_UNSET;
initialPlaylistLoader.release();
initialPlaylistLoader = null;
@@ -181,8 +184,8 @@ public final class DefaultHlsPlaylistTracker
@Override
@Nullable
- public HlsMasterPlaylist getMasterPlaylist() {
- return masterPlaylist;
+ public HlsMultivariantPlaylist getMultivariantPlaylist() {
+ return multivariantPlaylist;
}
@Override
@@ -245,18 +248,19 @@ public final class DefaultHlsPlaylistTracker
public void onLoadCompleted(
ParsingLoadable loadable, long elapsedRealtimeMs, long loadDurationMs) {
HlsPlaylist result = loadable.getResult();
- HlsMasterPlaylist masterPlaylist;
+ HlsMultivariantPlaylist multivariantPlaylist;
boolean isMediaPlaylist = result instanceof HlsMediaPlaylist;
if (isMediaPlaylist) {
- masterPlaylist = HlsMasterPlaylist.createSingleVariantMasterPlaylist(result.baseUri);
- } else /* result instanceof HlsMasterPlaylist */ {
- masterPlaylist = (HlsMasterPlaylist) result;
+ multivariantPlaylist =
+ HlsMultivariantPlaylist.createSingleVariantMultivariantPlaylist(result.baseUri);
+ } else /* result instanceof HlsMultivariantPlaylist */ {
+ multivariantPlaylist = (HlsMultivariantPlaylist) result;
}
- this.masterPlaylist = masterPlaylist;
- primaryMediaPlaylistUrl = masterPlaylist.variants.get(0).url;
+ this.multivariantPlaylist = multivariantPlaylist;
+ primaryMediaPlaylistUrl = multivariantPlaylist.variants.get(0).url;
// Add a temporary playlist listener for loading the first primary playlist.
listeners.add(new FirstPrimaryMediaPlaylistListener());
- createBundles(masterPlaylist.mediaPlaylistUrls);
+ createBundles(multivariantPlaylist.mediaPlaylistUrls);
LoadEventInfo loadEventInfo =
new LoadEventInfo(
loadable.loadTaskId,
@@ -329,7 +333,7 @@ public final class DefaultHlsPlaylistTracker
// Internal methods.
private boolean maybeSelectNewPrimaryUrl() {
- List variants = masterPlaylist.variants;
+ List variants = multivariantPlaylist.variants;
int variantsSize = variants.size();
long currentTimeMs = SystemClock.elapsedRealtime();
for (int i = 0; i < variantsSize; i++) {
@@ -384,9 +388,12 @@ public final class DefaultHlsPlaylistTracker
return newPrimaryPlaylistUri;
}
- /** Returns whether any of the variants in the master playlist have the specified playlist URL. */
+ /**
+ * Returns whether any of the variants in the multivariant playlist have the specified playlist
+ * URL.
+ */
private boolean isVariantUrl(Uri playlistUrl) {
- List variants = masterPlaylist.variants;
+ List variants = multivariantPlaylist.variants;
for (int i = 0; i < variants.size(); i++) {
if (playlistUrl.equals(variants.get(i).url)) {
return true;
@@ -689,7 +696,7 @@ public final class DefaultHlsPlaylistTracker
private void loadPlaylistImmediately(Uri playlistRequestUri) {
ParsingLoadable.Parser mediaPlaylistParser =
- playlistParserFactory.createPlaylistParser(masterPlaylist, playlistSnapshot);
+ playlistParserFactory.createPlaylistParser(multivariantPlaylist, playlistSnapshot);
ParsingLoadable mediaPlaylistLoadable =
new ParsingLoadable<>(
mediaPlaylistDataSource,
@@ -825,7 +832,7 @@ public final class DefaultHlsPlaylistTracker
if (primaryMediaPlaylistSnapshot == null) {
long nowMs = SystemClock.elapsedRealtime();
int variantExclusionCounter = 0;
- List variants = castNonNull(masterPlaylist).variants;
+ List variants = castNonNull(multivariantPlaylist).variants;
for (int i = 0; i < variants.size(); i++) {
@Nullable
MediaPlaylistBundle mediaPlaylistBundle = playlistBundles.get(variants.get(i).url);
@@ -837,7 +844,7 @@ public final class DefaultHlsPlaylistTracker
new LoadErrorHandlingPolicy.FallbackOptions(
/* numberOfLocations= */ 1,
/* numberOfExcludedLocations= */ 0,
- /* numberOfTracks= */ masterPlaylist.variants.size(),
+ /* numberOfTracks= */ multivariantPlaylist.variants.size(),
/* numberOfExcludedTracks= */ variantExclusionCounter);
@Nullable
LoadErrorHandlingPolicy.FallbackSelection fallbackSelection =
diff --git a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/FilteringHlsPlaylistParserFactory.java b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/FilteringHlsPlaylistParserFactory.java
index 35146e0ed3..a4ad594f3e 100644
--- a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/FilteringHlsPlaylistParserFactory.java
+++ b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/FilteringHlsPlaylistParserFactory.java
@@ -51,9 +51,10 @@ public final class FilteringHlsPlaylistParserFactory implements HlsPlaylistParse
@Override
public ParsingLoadable.Parser createPlaylistParser(
- HlsMasterPlaylist masterPlaylist, @Nullable HlsMediaPlaylist previousMediaPlaylist) {
+ HlsMultivariantPlaylist multivariantPlaylist,
+ @Nullable HlsMediaPlaylist previousMediaPlaylist) {
return new FilteringManifestParser<>(
- hlsPlaylistParserFactory.createPlaylistParser(masterPlaylist, previousMediaPlaylist),
+ hlsPlaylistParserFactory.createPlaylistParser(multivariantPlaylist, previousMediaPlaylist),
streamKeys);
}
}
diff --git a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsMasterPlaylist.java b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsMasterPlaylist.java
index b6aa0b512d..6ddc2c4387 100644
--- a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsMasterPlaylist.java
+++ b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsMasterPlaylist.java
@@ -15,183 +15,24 @@
*/
package androidx.media3.exoplayer.hls.playlist;
-import android.net.Uri;
import androidx.annotation.Nullable;
import androidx.media3.common.DrmInitData;
import androidx.media3.common.Format;
-import androidx.media3.common.MimeTypes;
-import androidx.media3.common.StreamKey;
import androidx.media3.common.util.UnstableApi;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
-/** Represents an HLS master playlist. */
+/** @deprecated Use {@link HlsMultivariantPlaylist} instead. */
@UnstableApi
-public final class HlsMasterPlaylist extends HlsPlaylist {
-
- /** Represents an empty master playlist, from which no attributes can be inherited. */
- public static final HlsMasterPlaylist EMPTY =
- new HlsMasterPlaylist(
- /* baseUri= */ "",
- /* tags= */ Collections.emptyList(),
- /* variants= */ Collections.emptyList(),
- /* videos= */ Collections.emptyList(),
- /* audios= */ Collections.emptyList(),
- /* subtitles= */ Collections.emptyList(),
- /* closedCaptions= */ Collections.emptyList(),
- /* muxedAudioFormat= */ null,
- /* muxedCaptionFormats= */ Collections.emptyList(),
- /* hasIndependentSegments= */ false,
- /* variableDefinitions= */ Collections.emptyMap(),
- /* sessionKeyDrmInitData= */ Collections.emptyList());
-
- // These constants must not be changed because they are persisted in offline stream keys.
- public static final int GROUP_INDEX_VARIANT = 0;
- public static final int GROUP_INDEX_AUDIO = 1;
- public static final int GROUP_INDEX_SUBTITLE = 2;
-
- /** A variant (i.e. an #EXT-X-STREAM-INF tag) in a master playlist. */
- public static final class Variant {
-
- /** The variant's url. */
- public final Uri url;
-
- /** Format information associated with this variant. */
- public final Format format;
-
- /** The video rendition group referenced by this variant, or {@code null}. */
- @Nullable public final String videoGroupId;
-
- /** The audio rendition group referenced by this variant, or {@code null}. */
- @Nullable public final String audioGroupId;
-
- /** The subtitle rendition group referenced by this variant, or {@code null}. */
- @Nullable public final String subtitleGroupId;
-
- /** The caption rendition group referenced by this variant, or {@code null}. */
- @Nullable public final String captionGroupId;
-
- /**
- * @param url See {@link #url}.
- * @param format See {@link #format}.
- * @param videoGroupId See {@link #videoGroupId}.
- * @param audioGroupId See {@link #audioGroupId}.
- * @param subtitleGroupId See {@link #subtitleGroupId}.
- * @param captionGroupId See {@link #captionGroupId}.
- */
- public Variant(
- Uri url,
- Format format,
- @Nullable String videoGroupId,
- @Nullable String audioGroupId,
- @Nullable String subtitleGroupId,
- @Nullable String captionGroupId) {
- this.url = url;
- this.format = format;
- this.videoGroupId = videoGroupId;
- this.audioGroupId = audioGroupId;
- this.subtitleGroupId = subtitleGroupId;
- this.captionGroupId = captionGroupId;
- }
-
- /**
- * Creates a variant for a given media playlist url.
- *
- * @param url The media playlist url.
- * @return The variant instance.
- */
- public static Variant createMediaPlaylistVariantUrl(Uri url) {
- Format format =
- new Format.Builder().setId("0").setContainerMimeType(MimeTypes.APPLICATION_M3U8).build();
- return new Variant(
- url,
- format,
- /* videoGroupId= */ null,
- /* audioGroupId= */ null,
- /* subtitleGroupId= */ null,
- /* captionGroupId= */ null);
- }
-
- /** Returns a copy of this instance with the given {@link Format}. */
- public Variant copyWithFormat(Format format) {
- return new Variant(url, format, videoGroupId, audioGroupId, subtitleGroupId, captionGroupId);
- }
- }
-
- /** A rendition (i.e. an #EXT-X-MEDIA tag) in a master playlist. */
- public static final class Rendition {
-
- /** The rendition's url, or null if the tag does not have a URI attribute. */
- @Nullable public final Uri url;
-
- /** Format information associated with this rendition. */
- public final Format format;
-
- /** The group to which this rendition belongs. */
- public final String groupId;
-
- /** The name of the rendition. */
- public final String name;
-
- /**
- * @param url See {@link #url}.
- * @param format See {@link #format}.
- * @param groupId See {@link #groupId}.
- * @param name See {@link #name}.
- */
- public Rendition(@Nullable Uri url, Format format, String groupId, String name) {
- this.url = url;
- this.format = format;
- this.groupId = groupId;
- this.name = name;
- }
- }
-
- /** All of the media playlist URLs referenced by the playlist. */
- public final List mediaPlaylistUrls;
- /** The variants declared by the playlist. */
- public final List variants;
- /** The video renditions declared by the playlist. */
- public final List videos;
- /** The audio renditions declared by the playlist. */
- public final List audios;
- /** The subtitle renditions declared by the playlist. */
- public final List subtitles;
- /** The closed caption renditions declared by the playlist. */
- public final List closedCaptions;
+@Deprecated
+public final class HlsMasterPlaylist extends HlsMultivariantPlaylist {
/**
- * The format of the audio muxed in the variants. May be null if the playlist does not declare any
- * muxed audio.
- */
- @Nullable public final Format muxedAudioFormat;
- /**
- * The format of the closed captions declared by the playlist. May be empty if the playlist
- * explicitly declares no captions are available, or null if the playlist does not declare any
- * captions information.
- */
- @Nullable public final List muxedCaptionFormats;
- /** Contains variable definitions, as defined by the #EXT-X-DEFINE tag. */
- public final Map variableDefinitions;
- /** DRM initialization data derived from #EXT-X-SESSION-KEY tags. */
- public final List sessionKeyDrmInitData;
-
- /**
- * @param baseUri See {@link #baseUri}.
- * @param tags See {@link #tags}.
- * @param variants See {@link #variants}.
- * @param videos See {@link #videos}.
- * @param audios See {@link #audios}.
- * @param subtitles See {@link #subtitles}.
- * @param closedCaptions See {@link #closedCaptions}.
- * @param muxedAudioFormat See {@link #muxedAudioFormat}.
- * @param muxedCaptionFormats See {@link #muxedCaptionFormats}.
- * @param hasIndependentSegments See {@link #hasIndependentSegments}.
- * @param variableDefinitions See {@link #variableDefinitions}.
- * @param sessionKeyDrmInitData See {@link #sessionKeyDrmInitData}.
+ * Creates an HLS multivariant playlist.
+ *
+ * @deprecated Use {@link HlsMultivariantPlaylist#HlsMultivariantPlaylist} instead.
*/
+ @Deprecated
public HlsMasterPlaylist(
String baseUri,
List tags,
@@ -205,117 +46,18 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
boolean hasIndependentSegments,
Map variableDefinitions,
List sessionKeyDrmInitData) {
- super(baseUri, tags, hasIndependentSegments);
- this.mediaPlaylistUrls =
- Collections.unmodifiableList(
- getMediaPlaylistUrls(variants, videos, audios, subtitles, closedCaptions));
- this.variants = Collections.unmodifiableList(variants);
- this.videos = Collections.unmodifiableList(videos);
- this.audios = Collections.unmodifiableList(audios);
- this.subtitles = Collections.unmodifiableList(subtitles);
- this.closedCaptions = Collections.unmodifiableList(closedCaptions);
- this.muxedAudioFormat = muxedAudioFormat;
- this.muxedCaptionFormats =
- muxedCaptionFormats != null ? Collections.unmodifiableList(muxedCaptionFormats) : null;
- this.variableDefinitions = Collections.unmodifiableMap(variableDefinitions);
- this.sessionKeyDrmInitData = Collections.unmodifiableList(sessionKeyDrmInitData);
- }
-
- @Override
- public HlsMasterPlaylist copy(List streamKeys) {
- return new HlsMasterPlaylist(
+ super(
baseUri,
tags,
- copyStreams(variants, GROUP_INDEX_VARIANT, streamKeys),
- // TODO: Allow stream keys to specify video renditions to be retained.
- /* videos= */ Collections.emptyList(),
- copyStreams(audios, GROUP_INDEX_AUDIO, streamKeys),
- copyStreams(subtitles, GROUP_INDEX_SUBTITLE, streamKeys),
- // TODO: Update to retain all closed captions.
- /* closedCaptions= */ Collections.emptyList(),
+ variants,
+ videos,
+ audios,
+ subtitles,
+ closedCaptions,
muxedAudioFormat,
muxedCaptionFormats,
hasIndependentSegments,
variableDefinitions,
sessionKeyDrmInitData);
}
-
- /**
- * Creates a playlist with a single variant.
- *
- * @param variantUrl The url of the single variant.
- * @return A master playlist with a single variant for the provided url.
- */
- public static HlsMasterPlaylist createSingleVariantMasterPlaylist(String variantUrl) {
- List variant =
- Collections.singletonList(Variant.createMediaPlaylistVariantUrl(Uri.parse(variantUrl)));
- return new HlsMasterPlaylist(
- /* baseUri= */ "",
- /* tags= */ Collections.emptyList(),
- variant,
- /* videos= */ Collections.emptyList(),
- /* audios= */ Collections.emptyList(),
- /* subtitles= */ Collections.emptyList(),
- /* closedCaptions= */ Collections.emptyList(),
- /* muxedAudioFormat= */ null,
- /* muxedCaptionFormats= */ null,
- /* hasIndependentSegments= */ false,
- /* variableDefinitions= */ Collections.emptyMap(),
- /* sessionKeyDrmInitData= */ Collections.emptyList());
- }
-
- private static List getMediaPlaylistUrls(
- List variants,
- List videos,
- List audios,
- List subtitles,
- List closedCaptions) {
- ArrayList mediaPlaylistUrls = new ArrayList<>();
- for (int i = 0; i < variants.size(); i++) {
- Uri uri = variants.get(i).url;
- if (!mediaPlaylistUrls.contains(uri)) {
- mediaPlaylistUrls.add(uri);
- }
- }
- addMediaPlaylistUrls(videos, mediaPlaylistUrls);
- addMediaPlaylistUrls(audios, mediaPlaylistUrls);
- addMediaPlaylistUrls(subtitles, mediaPlaylistUrls);
- addMediaPlaylistUrls(closedCaptions, mediaPlaylistUrls);
- return mediaPlaylistUrls;
- }
-
- private static void addMediaPlaylistUrls(List renditions, List out) {
- for (int i = 0; i < renditions.size(); i++) {
- Uri uri = renditions.get(i).url;
- if (uri != null && !out.contains(uri)) {
- out.add(uri);
- }
- }
- }
-
- private static List copyStreams(
- List streams, int groupIndex, List streamKeys) {
- List copiedStreams = new ArrayList<>(streamKeys.size());
- // TODO:
- // 1. When variants with the same URL are not de-duplicated, duplicates must not increment
- // trackIndex so as to avoid breaking stream keys that have been persisted for offline. All
- // duplicates should be copied if the first variant is copied, or discarded otherwise.
- // 2. When renditions with null URLs are permitted, they must not increment trackIndex so as to
- // avoid breaking stream keys that have been persisted for offline. All renitions with null
- // URLs should be copied. They may become unreachable if all variants that reference them are
- // removed, but this is OK.
- // 3. Renditions with URLs matching copied variants should always themselves be copied, even if
- // the corresponding stream key is omitted. Else we're throwing away information for no gain.
- for (int i = 0; i < streams.size(); i++) {
- T stream = streams.get(i);
- for (int j = 0; j < streamKeys.size(); j++) {
- StreamKey streamKey = streamKeys.get(j);
- if (streamKey.groupIndex == groupIndex && streamKey.streamIndex == i) {
- copiedStreams.add(stream);
- break;
- }
- }
- }
- return copiedStreams;
- }
}
diff --git a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsMultivariantPlaylist.java b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsMultivariantPlaylist.java
new file mode 100644
index 0000000000..0d34d89851
--- /dev/null
+++ b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsMultivariantPlaylist.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.media3.exoplayer.hls.playlist;
+
+import android.net.Uri;
+import androidx.annotation.Nullable;
+import androidx.media3.common.DrmInitData;
+import androidx.media3.common.Format;
+import androidx.media3.common.MimeTypes;
+import androidx.media3.common.StreamKey;
+import androidx.media3.common.util.UnstableApi;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/** Represents an HLS multivariant playlist. */
+// TODO(b/211458101): Make non-final once HlsMasterPlaylist is removed.
+@UnstableApi
+public class HlsMultivariantPlaylist extends HlsPlaylist {
+
+ /** Represents an empty multivariant playlist, from which no attributes can be inherited. */
+ public static final HlsMultivariantPlaylist EMPTY =
+ new HlsMultivariantPlaylist(
+ /* baseUri= */ "",
+ /* tags= */ Collections.emptyList(),
+ /* variants= */ Collections.emptyList(),
+ /* videos= */ Collections.emptyList(),
+ /* audios= */ Collections.emptyList(),
+ /* subtitles= */ Collections.emptyList(),
+ /* closedCaptions= */ Collections.emptyList(),
+ /* muxedAudioFormat= */ null,
+ /* muxedCaptionFormats= */ Collections.emptyList(),
+ /* hasIndependentSegments= */ false,
+ /* variableDefinitions= */ Collections.emptyMap(),
+ /* sessionKeyDrmInitData= */ Collections.emptyList());
+
+ // These constants must not be changed because they are persisted in offline stream keys.
+ public static final int GROUP_INDEX_VARIANT = 0;
+ public static final int GROUP_INDEX_AUDIO = 1;
+ public static final int GROUP_INDEX_SUBTITLE = 2;
+
+ /** A variant (i.e. an #EXT-X-STREAM-INF tag) in a multivariant playlist. */
+ public static final class Variant {
+
+ /** The variant's url. */
+ public final Uri url;
+
+ /** Format information associated with this variant. */
+ public final Format format;
+
+ /** The video rendition group referenced by this variant, or {@code null}. */
+ @Nullable public final String videoGroupId;
+
+ /** The audio rendition group referenced by this variant, or {@code null}. */
+ @Nullable public final String audioGroupId;
+
+ /** The subtitle rendition group referenced by this variant, or {@code null}. */
+ @Nullable public final String subtitleGroupId;
+
+ /** The caption rendition group referenced by this variant, or {@code null}. */
+ @Nullable public final String captionGroupId;
+
+ /**
+ * @param url See {@link #url}.
+ * @param format See {@link #format}.
+ * @param videoGroupId See {@link #videoGroupId}.
+ * @param audioGroupId See {@link #audioGroupId}.
+ * @param subtitleGroupId See {@link #subtitleGroupId}.
+ * @param captionGroupId See {@link #captionGroupId}.
+ */
+ public Variant(
+ Uri url,
+ Format format,
+ @Nullable String videoGroupId,
+ @Nullable String audioGroupId,
+ @Nullable String subtitleGroupId,
+ @Nullable String captionGroupId) {
+ this.url = url;
+ this.format = format;
+ this.videoGroupId = videoGroupId;
+ this.audioGroupId = audioGroupId;
+ this.subtitleGroupId = subtitleGroupId;
+ this.captionGroupId = captionGroupId;
+ }
+
+ /**
+ * Creates a variant for a given media playlist url.
+ *
+ * @param url The media playlist url.
+ * @return The variant instance.
+ */
+ public static Variant createMediaPlaylistVariantUrl(Uri url) {
+ Format format =
+ new Format.Builder().setId("0").setContainerMimeType(MimeTypes.APPLICATION_M3U8).build();
+ return new Variant(
+ url,
+ format,
+ /* videoGroupId= */ null,
+ /* audioGroupId= */ null,
+ /* subtitleGroupId= */ null,
+ /* captionGroupId= */ null);
+ }
+
+ /** Returns a copy of this instance with the given {@link Format}. */
+ public Variant copyWithFormat(Format format) {
+ return new Variant(url, format, videoGroupId, audioGroupId, subtitleGroupId, captionGroupId);
+ }
+ }
+
+ /** A rendition (i.e. an #EXT-X-MEDIA tag) in a multivariant playlist. */
+ public static final class Rendition {
+
+ /** The rendition's url, or null if the tag does not have a URI attribute. */
+ @Nullable public final Uri url;
+
+ /** Format information associated with this rendition. */
+ public final Format format;
+
+ /** The group to which this rendition belongs. */
+ public final String groupId;
+
+ /** The name of the rendition. */
+ public final String name;
+
+ /**
+ * @param url See {@link #url}.
+ * @param format See {@link #format}.
+ * @param groupId See {@link #groupId}.
+ * @param name See {@link #name}.
+ */
+ public Rendition(@Nullable Uri url, Format format, String groupId, String name) {
+ this.url = url;
+ this.format = format;
+ this.groupId = groupId;
+ this.name = name;
+ }
+ }
+
+ /** All of the media playlist URLs referenced by the playlist. */
+ public final List mediaPlaylistUrls;
+ /** The variants declared by the playlist. */
+ public final List variants;
+ /** The video renditions declared by the playlist. */
+ public final List videos;
+ /** The audio renditions declared by the playlist. */
+ public final List audios;
+ /** The subtitle renditions declared by the playlist. */
+ public final List subtitles;
+ /** The closed caption renditions declared by the playlist. */
+ public final List closedCaptions;
+
+ /**
+ * The format of the audio muxed in the variants. May be null if the playlist does not declare any
+ * muxed audio.
+ */
+ @Nullable public final Format muxedAudioFormat;
+ /**
+ * The format of the closed captions declared by the playlist. May be empty if the playlist
+ * explicitly declares no captions are available, or null if the playlist does not declare any
+ * captions information.
+ */
+ @Nullable public final List muxedCaptionFormats;
+ /** Contains variable definitions, as defined by the #EXT-X-DEFINE tag. */
+ public final Map variableDefinitions;
+ /** DRM initialization data derived from #EXT-X-SESSION-KEY tags. */
+ public final List sessionKeyDrmInitData;
+
+ /**
+ * @param baseUri See {@link #baseUri}.
+ * @param tags See {@link #tags}.
+ * @param variants See {@link #variants}.
+ * @param videos See {@link #videos}.
+ * @param audios See {@link #audios}.
+ * @param subtitles See {@link #subtitles}.
+ * @param closedCaptions See {@link #closedCaptions}.
+ * @param muxedAudioFormat See {@link #muxedAudioFormat}.
+ * @param muxedCaptionFormats See {@link #muxedCaptionFormats}.
+ * @param hasIndependentSegments See {@link #hasIndependentSegments}.
+ * @param variableDefinitions See {@link #variableDefinitions}.
+ * @param sessionKeyDrmInitData See {@link #sessionKeyDrmInitData}.
+ */
+ public HlsMultivariantPlaylist(
+ String baseUri,
+ List tags,
+ List variants,
+ List videos,
+ List audios,
+ List subtitles,
+ List closedCaptions,
+ @Nullable Format muxedAudioFormat,
+ @Nullable List muxedCaptionFormats,
+ boolean hasIndependentSegments,
+ Map variableDefinitions,
+ List sessionKeyDrmInitData) {
+ super(baseUri, tags, hasIndependentSegments);
+ this.mediaPlaylistUrls =
+ Collections.unmodifiableList(
+ getMediaPlaylistUrls(variants, videos, audios, subtitles, closedCaptions));
+ this.variants = Collections.unmodifiableList(variants);
+ this.videos = Collections.unmodifiableList(videos);
+ this.audios = Collections.unmodifiableList(audios);
+ this.subtitles = Collections.unmodifiableList(subtitles);
+ this.closedCaptions = Collections.unmodifiableList(closedCaptions);
+ this.muxedAudioFormat = muxedAudioFormat;
+ this.muxedCaptionFormats =
+ muxedCaptionFormats != null ? Collections.unmodifiableList(muxedCaptionFormats) : null;
+ this.variableDefinitions = Collections.unmodifiableMap(variableDefinitions);
+ this.sessionKeyDrmInitData = Collections.unmodifiableList(sessionKeyDrmInitData);
+ }
+
+ @Override
+ public HlsMultivariantPlaylist copy(List streamKeys) {
+ return new HlsMultivariantPlaylist(
+ baseUri,
+ tags,
+ copyStreams(variants, GROUP_INDEX_VARIANT, streamKeys),
+ // TODO: Allow stream keys to specify video renditions to be retained.
+ /* videos= */ Collections.emptyList(),
+ copyStreams(audios, GROUP_INDEX_AUDIO, streamKeys),
+ copyStreams(subtitles, GROUP_INDEX_SUBTITLE, streamKeys),
+ // TODO: Update to retain all closed captions.
+ /* closedCaptions= */ Collections.emptyList(),
+ muxedAudioFormat,
+ muxedCaptionFormats,
+ hasIndependentSegments,
+ variableDefinitions,
+ sessionKeyDrmInitData);
+ }
+
+ /**
+ * Creates a playlist with a single variant.
+ *
+ * @param variantUrl The url of the single variant.
+ * @return A multivariant playlist with a single variant for the provided url.
+ */
+ public static HlsMultivariantPlaylist createSingleVariantMultivariantPlaylist(String variantUrl) {
+ List variant =
+ Collections.singletonList(Variant.createMediaPlaylistVariantUrl(Uri.parse(variantUrl)));
+ return new HlsMultivariantPlaylist(
+ /* baseUri= */ "",
+ /* tags= */ Collections.emptyList(),
+ variant,
+ /* videos= */ Collections.emptyList(),
+ /* audios= */ Collections.emptyList(),
+ /* subtitles= */ Collections.emptyList(),
+ /* closedCaptions= */ Collections.emptyList(),
+ /* muxedAudioFormat= */ null,
+ /* muxedCaptionFormats= */ null,
+ /* hasIndependentSegments= */ false,
+ /* variableDefinitions= */ Collections.emptyMap(),
+ /* sessionKeyDrmInitData= */ Collections.emptyList());
+ }
+
+ private static List getMediaPlaylistUrls(
+ List variants,
+ List videos,
+ List audios,
+ List subtitles,
+ List closedCaptions) {
+ ArrayList mediaPlaylistUrls = new ArrayList<>();
+ for (int i = 0; i < variants.size(); i++) {
+ Uri uri = variants.get(i).url;
+ if (!mediaPlaylistUrls.contains(uri)) {
+ mediaPlaylistUrls.add(uri);
+ }
+ }
+ addMediaPlaylistUrls(videos, mediaPlaylistUrls);
+ addMediaPlaylistUrls(audios, mediaPlaylistUrls);
+ addMediaPlaylistUrls(subtitles, mediaPlaylistUrls);
+ addMediaPlaylistUrls(closedCaptions, mediaPlaylistUrls);
+ return mediaPlaylistUrls;
+ }
+
+ private static void addMediaPlaylistUrls(List renditions, List out) {
+ for (int i = 0; i < renditions.size(); i++) {
+ Uri uri = renditions.get(i).url;
+ if (uri != null && !out.contains(uri)) {
+ out.add(uri);
+ }
+ }
+ }
+
+ private static List copyStreams(
+ List streams, int groupIndex, List streamKeys) {
+ List copiedStreams = new ArrayList<>(streamKeys.size());
+ // TODO:
+ // 1. When variants with the same URL are not de-duplicated, duplicates must not increment
+ // trackIndex so as to avoid breaking stream keys that have been persisted for offline. All
+ // duplicates should be copied if the first variant is copied, or discarded otherwise.
+ // 2. When renditions with null URLs are permitted, they must not increment trackIndex so as to
+ // avoid breaking stream keys that have been persisted for offline. All renitions with null
+ // URLs should be copied. They may become unreachable if all variants that reference them are
+ // removed, but this is OK.
+ // 3. Renditions with URLs matching copied variants should always themselves be copied, even if
+ // the corresponding stream key is omitted. Else we're throwing away information for no gain.
+ for (int i = 0; i < streams.size(); i++) {
+ T stream = streams.get(i);
+ for (int j = 0; j < streamKeys.size(); j++) {
+ StreamKey streamKey = streamKeys.get(j);
+ if (streamKey.groupIndex == groupIndex && streamKey.streamIndex == i) {
+ copiedStreams.add(stream);
+ break;
+ }
+ }
+ }
+ return copiedStreams;
+ }
+}
diff --git a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsPlaylistParser.java b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsPlaylistParser.java
index e5e2596654..c1e48a068b 100644
--- a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsPlaylistParser.java
+++ b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsPlaylistParser.java
@@ -37,11 +37,11 @@ import androidx.media3.common.util.UriUtil;
import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.hls.HlsTrackMetadataEntry;
import androidx.media3.exoplayer.hls.HlsTrackMetadataEntry.VariantInfo;
-import androidx.media3.exoplayer.hls.playlist.HlsMasterPlaylist.Rendition;
-import androidx.media3.exoplayer.hls.playlist.HlsMasterPlaylist.Variant;
import androidx.media3.exoplayer.hls.playlist.HlsMediaPlaylist.Part;
import androidx.media3.exoplayer.hls.playlist.HlsMediaPlaylist.RenditionReport;
import androidx.media3.exoplayer.hls.playlist.HlsMediaPlaylist.Segment;
+import androidx.media3.exoplayer.hls.playlist.HlsMultivariantPlaylist.Rendition;
+import androidx.media3.exoplayer.hls.playlist.HlsMultivariantPlaylist.Variant;
import androidx.media3.exoplayer.upstream.ParsingLoadable;
import androidx.media3.extractor.mp4.PsshAtomUtil;
import com.google.common.collect.Iterables;
@@ -225,28 +225,30 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser> urlToVariantInfos = new HashMap<>();
HashMap variableDefinitions = new HashMap<>();
ArrayList variants = new ArrayList<>();
@@ -580,7 +582,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser variableDefinitions = new HashMap<>();
@@ -750,11 +752,11 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser createPlaylistParser(
- HlsMasterPlaylist masterPlaylist, @Nullable HlsMediaPlaylist previousMediaPlaylist);
+ HlsMultivariantPlaylist multivariantPlaylist,
+ @Nullable HlsMediaPlaylist previousMediaPlaylist);
}
diff --git a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsPlaylistTracker.java b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsPlaylistTracker.java
index d12b3b36fe..d7eff3ca05 100644
--- a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsPlaylistTracker.java
+++ b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsPlaylistTracker.java
@@ -30,8 +30,8 @@ import java.io.IOException;
* The playlist tracker is responsible for exposing the seeking window, which is defined by the
* segments that one of the playlists exposes. This playlist is called primary and needs to be
* periodically refreshed in the case of live streams. Note that the primary playlist is one of the
- * media playlists while the master playlist is an optional kind of playlist defined by the HLS
- * specification (RFC 8216).
+ * media playlists while the multivariant playlist is an optional kind of playlist defined by the
+ * HLS specification (RFC 8216).
*
*
Playlist loads might encounter errors. The tracker may choose to exclude them to ensure a
* primary playlist is always available.
@@ -122,8 +122,8 @@ public interface HlsPlaylistTracker {
*
Must be called from the playback thread. A tracker may be restarted after a {@link #stop()}
* call.
*
- * @param initialPlaylistUri Uri of the HLS stream. Can point to a media playlist or a master
- * playlist.
+ * @param initialPlaylistUri Uri of the HLS stream. Can point to a media playlist or a
+ * multivariant playlist.
* @param eventDispatcher A dispatcher to notify of events.
* @param primaryPlaylistListener A callback for the primary playlist change events.
*/
@@ -154,15 +154,15 @@ public interface HlsPlaylistTracker {
void removeListener(PlaylistEventListener listener);
/**
- * Returns the master playlist.
+ * Returns the multivariant playlist.
*
- *
If the uri passed to {@link #start} points to a media playlist, an {@link HlsMasterPlaylist}
- * with a single variant for said media playlist is returned.
+ *
If the uri passed to {@link #start} points to a media playlist, an {@link
+ * HlsMultivariantPlaylist} with a single variant for said media playlist is returned.
*
- * @return The master playlist. Null if the initial playlist has yet to be loaded.
+ * @return The multivariant playlist. Null if the initial playlist has yet to be loaded.
*/
@Nullable
- HlsMasterPlaylist getMasterPlaylist();
+ HlsMultivariantPlaylist getMultivariantPlaylist();
/**
* Returns the most recent snapshot available of the playlist referenced by the provided {@link
@@ -194,8 +194,8 @@ public interface HlsPlaylistTracker {
boolean isSnapshotValid(Uri url);
/**
- * If the tracker is having trouble refreshing the master playlist or the primary playlist, this
- * method throws the underlying error. Otherwise, does nothing.
+ * If the tracker is having trouble refreshing the multivariant playlist or the primary playlist,
+ * this method throws the underlying error. Otherwise, does nothing.
*
* @throws IOException The underlying error.
*/
diff --git a/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/HlsMediaPeriodTest.java b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/HlsMediaPeriodTest.java
index 1ffa5e7339..ed2afa8107 100644
--- a/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/HlsMediaPeriodTest.java
+++ b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/HlsMediaPeriodTest.java
@@ -27,9 +27,9 @@ import androidx.media3.datasource.TransferListener;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
import androidx.media3.exoplayer.drm.DrmSessionManager;
-import androidx.media3.exoplayer.hls.playlist.HlsMasterPlaylist;
-import androidx.media3.exoplayer.hls.playlist.HlsMasterPlaylist.Rendition;
-import androidx.media3.exoplayer.hls.playlist.HlsMasterPlaylist.Variant;
+import androidx.media3.exoplayer.hls.playlist.HlsMultivariantPlaylist;
+import androidx.media3.exoplayer.hls.playlist.HlsMultivariantPlaylist.Rendition;
+import androidx.media3.exoplayer.hls.playlist.HlsMultivariantPlaylist.Variant;
import androidx.media3.exoplayer.hls.playlist.HlsPlaylist;
import androidx.media3.exoplayer.hls.playlist.HlsPlaylistTracker;
import androidx.media3.exoplayer.source.CompositeSequenceableLoaderFactory;
@@ -51,9 +51,9 @@ import org.junit.runner.RunWith;
public final class HlsMediaPeriodTest {
@Test
- public void getSteamKeys_isCompatibleWithHlsMasterPlaylistFilter() {
- HlsMasterPlaylist testMasterPlaylist =
- createMasterPlaylist(
+ public void getSteamKeys_isCompatibleWithHlsMultivariantPlaylistFilter() {
+ HlsMultivariantPlaylist testMultivariantPlaylist =
+ createMultivariantPlaylist(
/* variants= */ Arrays.asList(
createAudioOnlyVariant(/* peakBitrate= */ 10000),
createMuxedVideoAudioVariant(/* peakBitrate= */ 200000),
@@ -76,7 +76,8 @@ public final class HlsMediaPeriodTest {
HlsDataSourceFactory mockDataSourceFactory = mock(HlsDataSourceFactory.class);
when(mockDataSourceFactory.createDataSource(anyInt())).thenReturn(mock(DataSource.class));
HlsPlaylistTracker mockPlaylistTracker = mock(HlsPlaylistTracker.class);
- when(mockPlaylistTracker.getMasterPlaylist()).thenReturn((HlsMasterPlaylist) playlist);
+ when(mockPlaylistTracker.getMultivariantPlaylist())
+ .thenReturn((HlsMultivariantPlaylist) playlist);
MediaPeriodId mediaPeriodId = new MediaPeriodId(/* periodUid= */ new Object());
return new HlsMediaPeriod(
mock(HlsExtractorFactory.class),
@@ -98,16 +99,16 @@ public final class HlsMediaPeriodTest {
};
MediaPeriodAsserts.assertGetStreamKeysAndManifestFilterIntegration(
- mediaPeriodFactory, testMasterPlaylist);
+ mediaPeriodFactory, testMultivariantPlaylist);
}
- private static HlsMasterPlaylist createMasterPlaylist(
+ private static HlsMultivariantPlaylist createMultivariantPlaylist(
List variants,
List audios,
List subtitles,
Format muxedAudioFormat,
List muxedCaptionFormats) {
- return new HlsMasterPlaylist(
+ return new HlsMultivariantPlaylist(
"http://baseUri",
/* tags= */ Collections.emptyList(),
variants,
diff --git a/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/offline/HlsDownloadTestData.java b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/offline/HlsDownloadTestData.java
index 6257ceb926..eb92cb260f 100644
--- a/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/offline/HlsDownloadTestData.java
+++ b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/offline/HlsDownloadTestData.java
@@ -20,11 +20,11 @@ import com.google.common.base.Charsets;
/** Data for HLS downloading tests. */
/* package */ interface HlsDownloadTestData {
- String MASTER_PLAYLIST_URI = "test.m3u8";
- int MASTER_MEDIA_PLAYLIST_1_INDEX = 0;
- int MASTER_MEDIA_PLAYLIST_2_INDEX = 1;
- int MASTER_MEDIA_PLAYLIST_3_INDEX = 2;
- int MASTER_MEDIA_PLAYLIST_0_INDEX = 3;
+ String MULTIVARIANT_PLAYLIST_URI = "test.m3u8";
+ int MULTIVARIANT_MEDIA_PLAYLIST_1_INDEX = 0;
+ int MULTIVARIANT_MEDIA_PLAYLIST_2_INDEX = 1;
+ int MULTIVARIANT_MEDIA_PLAYLIST_3_INDEX = 2;
+ int MULTIVARIANT_MEDIA_PLAYLIST_0_INDEX = 3;
String MEDIA_PLAYLIST_0_DIR = "gear0/";
String MEDIA_PLAYLIST_0_URI = MEDIA_PLAYLIST_0_DIR + "prog_index.m3u8";
@@ -35,7 +35,7 @@ import com.google.common.base.Charsets;
String MEDIA_PLAYLIST_3_DIR = "gear3/";
String MEDIA_PLAYLIST_3_URI = MEDIA_PLAYLIST_3_DIR + "prog_index.m3u8";
- byte[] MASTER_PLAYLIST_DATA =
+ byte[] MULTIVARIANT_PLAYLIST_DATA =
("#EXTM3U\n"
+ "#EXT-X-STREAM-INF:BANDWIDTH=232370,CODECS=\"mp4a.40.2, avc1.4d4015\"\n"
+ MEDIA_PLAYLIST_1_URI
diff --git a/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/offline/HlsDownloaderTest.java b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/offline/HlsDownloaderTest.java
index 1842e76065..775323ce32 100644
--- a/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/offline/HlsDownloaderTest.java
+++ b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/offline/HlsDownloaderTest.java
@@ -17,10 +17,6 @@ package androidx.media3.exoplayer.hls.offline;
import static androidx.media3.exoplayer.hls.offline.HlsDownloadTestData.ENC_MEDIA_PLAYLIST_DATA;
import static androidx.media3.exoplayer.hls.offline.HlsDownloadTestData.ENC_MEDIA_PLAYLIST_URI;
-import static androidx.media3.exoplayer.hls.offline.HlsDownloadTestData.MASTER_MEDIA_PLAYLIST_1_INDEX;
-import static androidx.media3.exoplayer.hls.offline.HlsDownloadTestData.MASTER_MEDIA_PLAYLIST_2_INDEX;
-import static androidx.media3.exoplayer.hls.offline.HlsDownloadTestData.MASTER_PLAYLIST_DATA;
-import static androidx.media3.exoplayer.hls.offline.HlsDownloadTestData.MASTER_PLAYLIST_URI;
import static androidx.media3.exoplayer.hls.offline.HlsDownloadTestData.MEDIA_PLAYLIST_0_DIR;
import static androidx.media3.exoplayer.hls.offline.HlsDownloadTestData.MEDIA_PLAYLIST_0_URI;
import static androidx.media3.exoplayer.hls.offline.HlsDownloadTestData.MEDIA_PLAYLIST_1_DIR;
@@ -30,6 +26,10 @@ import static androidx.media3.exoplayer.hls.offline.HlsDownloadTestData.MEDIA_PL
import static androidx.media3.exoplayer.hls.offline.HlsDownloadTestData.MEDIA_PLAYLIST_3_DIR;
import static androidx.media3.exoplayer.hls.offline.HlsDownloadTestData.MEDIA_PLAYLIST_3_URI;
import static androidx.media3.exoplayer.hls.offline.HlsDownloadTestData.MEDIA_PLAYLIST_DATA;
+import static androidx.media3.exoplayer.hls.offline.HlsDownloadTestData.MULTIVARIANT_MEDIA_PLAYLIST_1_INDEX;
+import static androidx.media3.exoplayer.hls.offline.HlsDownloadTestData.MULTIVARIANT_MEDIA_PLAYLIST_2_INDEX;
+import static androidx.media3.exoplayer.hls.offline.HlsDownloadTestData.MULTIVARIANT_PLAYLIST_DATA;
+import static androidx.media3.exoplayer.hls.offline.HlsDownloadTestData.MULTIVARIANT_PLAYLIST_URI;
import static androidx.media3.test.utils.CacheAsserts.assertCacheEmpty;
import static androidx.media3.test.utils.CacheAsserts.assertCachedData;
import static com.google.common.truth.Truth.assertThat;
@@ -44,7 +44,7 @@ import androidx.media3.datasource.cache.Cache;
import androidx.media3.datasource.cache.CacheDataSource;
import androidx.media3.datasource.cache.NoOpCacheEvictor;
import androidx.media3.datasource.cache.SimpleCache;
-import androidx.media3.exoplayer.hls.playlist.HlsMasterPlaylist;
+import androidx.media3.exoplayer.hls.playlist.HlsMultivariantPlaylist;
import androidx.media3.exoplayer.offline.DefaultDownloaderFactory;
import androidx.media3.exoplayer.offline.DownloadRequest;
import androidx.media3.exoplayer.offline.Downloader;
@@ -83,7 +83,7 @@ public class HlsDownloaderTest {
progressListener = new ProgressListener();
fakeDataSet =
new FakeDataSet()
- .setData(MASTER_PLAYLIST_URI, MASTER_PLAYLIST_DATA)
+ .setData(MULTIVARIANT_PLAYLIST_URI, MULTIVARIANT_PLAYLIST_DATA)
.setData(MEDIA_PLAYLIST_1_URI, MEDIA_PLAYLIST_DATA)
.setRandomData(MEDIA_PLAYLIST_1_DIR + "fileSequence0.ts", 10)
.setRandomData(MEDIA_PLAYLIST_1_DIR + "fileSequence1.ts", 11)
@@ -122,7 +122,7 @@ public class HlsDownloaderTest {
@Test
public void counterMethods() throws Exception {
HlsDownloader downloader =
- getHlsDownloader(MASTER_PLAYLIST_URI, getKeys(MASTER_MEDIA_PLAYLIST_1_INDEX));
+ getHlsDownloader(MULTIVARIANT_PLAYLIST_URI, getKeys(MULTIVARIANT_MEDIA_PLAYLIST_1_INDEX));
downloader.download(progressListener);
progressListener.assertBytesDownloaded(MEDIA_PLAYLIST_DATA.length + 10 + 11 + 12);
@@ -131,14 +131,14 @@ public class HlsDownloaderTest {
@Test
public void downloadRepresentation() throws Exception {
HlsDownloader downloader =
- getHlsDownloader(MASTER_PLAYLIST_URI, getKeys(MASTER_MEDIA_PLAYLIST_1_INDEX));
+ getHlsDownloader(MULTIVARIANT_PLAYLIST_URI, getKeys(MULTIVARIANT_MEDIA_PLAYLIST_1_INDEX));
downloader.download(progressListener);
assertCachedData(
cache,
new CacheAsserts.RequestSet(fakeDataSet)
.subset(
- MASTER_PLAYLIST_URI,
+ MULTIVARIANT_PLAYLIST_URI,
MEDIA_PLAYLIST_1_URI,
MEDIA_PLAYLIST_1_DIR + "fileSequence0.ts",
MEDIA_PLAYLIST_1_DIR + "fileSequence1.ts",
@@ -149,8 +149,8 @@ public class HlsDownloaderTest {
public void downloadMultipleRepresentations() throws Exception {
HlsDownloader downloader =
getHlsDownloader(
- MASTER_PLAYLIST_URI,
- getKeys(MASTER_MEDIA_PLAYLIST_1_INDEX, MASTER_MEDIA_PLAYLIST_2_INDEX));
+ MULTIVARIANT_PLAYLIST_URI,
+ getKeys(MULTIVARIANT_MEDIA_PLAYLIST_1_INDEX, MULTIVARIANT_MEDIA_PLAYLIST_2_INDEX));
downloader.download(progressListener);
assertCachedData(cache, fakeDataSet);
@@ -169,7 +169,7 @@ public class HlsDownloaderTest {
.setRandomData(MEDIA_PLAYLIST_3_DIR + "fileSequence1.ts", 14)
.setRandomData(MEDIA_PLAYLIST_3_DIR + "fileSequence2.ts", 15);
- HlsDownloader downloader = getHlsDownloader(MASTER_PLAYLIST_URI, getKeys());
+ HlsDownloader downloader = getHlsDownloader(MULTIVARIANT_PLAYLIST_URI, getKeys());
downloader.download(progressListener);
assertCachedData(cache, fakeDataSet);
@@ -179,8 +179,8 @@ public class HlsDownloaderTest {
public void remove() throws Exception {
HlsDownloader downloader =
getHlsDownloader(
- MASTER_PLAYLIST_URI,
- getKeys(MASTER_MEDIA_PLAYLIST_1_INDEX, MASTER_MEDIA_PLAYLIST_2_INDEX));
+ MULTIVARIANT_PLAYLIST_URI,
+ getKeys(MULTIVARIANT_MEDIA_PLAYLIST_1_INDEX, MULTIVARIANT_MEDIA_PLAYLIST_2_INDEX));
downloader.download(progressListener);
downloader.remove();
@@ -231,7 +231,7 @@ public class HlsDownloaderTest {
private static ArrayList getKeys(int... variantIndices) {
ArrayList streamKeys = new ArrayList<>();
for (int variantIndex : variantIndices) {
- streamKeys.add(new StreamKey(HlsMasterPlaylist.GROUP_INDEX_VARIANT, variantIndex));
+ streamKeys.add(new StreamKey(HlsMultivariantPlaylist.GROUP_INDEX_VARIANT, variantIndex));
}
return streamKeys;
}
diff --git a/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/playlist/DefaultHlsPlaylistTrackerTest.java b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/playlist/DefaultHlsPlaylistTrackerTest.java
index bdef4223c4..cc537c9c00 100644
--- a/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/playlist/DefaultHlsPlaylistTrackerTest.java
+++ b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/playlist/DefaultHlsPlaylistTrackerTest.java
@@ -44,9 +44,10 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class DefaultHlsPlaylistTrackerTest {
- private static final String SAMPLE_M3U8_LIVE_MASTER = "media/m3u8/live_low_latency_master";
- private static final String SAMPLE_M3U8_LIVE_MASTER_MEDIA_URI_WITH_PARAM =
- "media/m3u8/live_low_latency_master_media_uri_with_param";
+ private static final String SAMPLE_M3U8_LIVE_MULTIVARIANT =
+ "media/m3u8/live_low_latency_multivariant";
+ private static final String SAMPLE_M3U8_LIVE_MULTIVARIANT_MEDIA_URI_WITH_PARAM =
+ "media/m3u8/live_low_latency_multivariant_media_uri_with_param";
private static final String SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_UNTIL =
"media/m3u8/live_low_latency_media_can_skip_until";
private static final String SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_UNTIL_FULL_RELOAD_AFTER_ERROR =
@@ -110,15 +111,15 @@ public class DefaultHlsPlaylistTrackerTest {
throws IOException, TimeoutException, InterruptedException {
List httpUrls =
enqueueWebServerResponses(
- new String[] {"master.m3u8", "/media0/playlist.m3u8", "/media0/playlist.m3u8"},
- getMockResponse(SAMPLE_M3U8_LIVE_MASTER),
+ new String[] {"multivariant.m3u8", "/media0/playlist.m3u8", "/media0/playlist.m3u8"},
+ getMockResponse(SAMPLE_M3U8_LIVE_MULTIVARIANT),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_NOT_SKIP),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_NOT_SKIP_NEXT));
List mediaPlaylists =
runPlaylistTrackerAndCollectMediaPlaylists(
new DefaultHttpDataSource.Factory(),
- Uri.parse(mockWebServer.url("/master.m3u8").toString()),
+ Uri.parse(mockWebServer.url("/multivariant.m3u8").toString()),
/* awaitedMediaPlaylistCount= */ 2);
assertRequestUrlsCalled(httpUrls);
@@ -141,16 +142,16 @@ public class DefaultHlsPlaylistTrackerTest {
List httpUrls =
enqueueWebServerResponses(
new String[] {
- "/master.m3u8", "/media0/playlist.m3u8", "/media0/playlist.m3u8?_HLS_skip=YES"
+ "/multivariant.m3u8", "/media0/playlist.m3u8", "/media0/playlist.m3u8?_HLS_skip=YES"
},
- getMockResponse(SAMPLE_M3U8_LIVE_MASTER),
+ getMockResponse(SAMPLE_M3U8_LIVE_MULTIVARIANT),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_UNTIL),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_SKIPPED));
List mediaPlaylists =
runPlaylistTrackerAndCollectMediaPlaylists(
new DefaultHttpDataSource.Factory(),
- Uri.parse(mockWebServer.url("/master.m3u8").toString()),
+ Uri.parse(mockWebServer.url("/multivariant.m3u8").toString()),
/* awaitedMediaPlaylistCount= */ 2);
assertRequestUrlsCalled(httpUrls);
@@ -175,12 +176,12 @@ public class DefaultHlsPlaylistTrackerTest {
List httpUrls =
enqueueWebServerResponses(
new String[] {
- "/master.m3u8",
+ "/multivariant.m3u8",
"/media0/playlist.m3u8",
"/media0/playlist.m3u8?_HLS_skip=YES",
"/media0/playlist.m3u8"
},
- getMockResponse(SAMPLE_M3U8_LIVE_MASTER),
+ getMockResponse(SAMPLE_M3U8_LIVE_MULTIVARIANT),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_UNTIL),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_SKIPPED_MEDIA_SEQUENCE_NO_OVERLAPPING),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_UNTIL_FULL_RELOAD_AFTER_ERROR));
@@ -188,7 +189,7 @@ public class DefaultHlsPlaylistTrackerTest {
List mediaPlaylists =
runPlaylistTrackerAndCollectMediaPlaylists(
new DefaultHttpDataSource.Factory(),
- Uri.parse(mockWebServer.url("/master.m3u8").toString()),
+ Uri.parse(mockWebServer.url("/multivariant.m3u8").toString()),
/* awaitedMediaPlaylistCount= */ 2);
assertRequestUrlsCalled(httpUrls);
@@ -206,16 +207,16 @@ public class DefaultHlsPlaylistTrackerTest {
List httpUrls =
enqueueWebServerResponses(
new String[] {
- "/master.m3u8", "/media0/playlist.m3u8", "/media0/playlist.m3u8?_HLS_skip=v2"
+ "/multivariant.m3u8", "/media0/playlist.m3u8", "/media0/playlist.m3u8?_HLS_skip=v2"
},
- getMockResponse(SAMPLE_M3U8_LIVE_MASTER),
+ getMockResponse(SAMPLE_M3U8_LIVE_MULTIVARIANT),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_DATERANGES),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_SKIPPED));
List mediaPlaylists =
runPlaylistTrackerAndCollectMediaPlaylists(
new DefaultHttpDataSource.Factory(),
- Uri.parse(mockWebServer.url("/master.m3u8").toString()),
+ Uri.parse(mockWebServer.url("/multivariant.m3u8").toString()),
/* awaitedMediaPlaylistCount= */ 2);
assertRequestUrlsCalled(httpUrls);
@@ -230,18 +231,18 @@ public class DefaultHlsPlaylistTrackerTest {
List httpUrls =
enqueueWebServerResponses(
new String[] {
- "/master.m3u8",
+ "/multivariant.m3u8",
"/media0/playlist.m3u8?param1=1¶m2=2",
"/media0/playlist.m3u8?param1=1¶m2=2&_HLS_skip=YES"
},
- getMockResponse(SAMPLE_M3U8_LIVE_MASTER_MEDIA_URI_WITH_PARAM),
+ getMockResponse(SAMPLE_M3U8_LIVE_MULTIVARIANT_MEDIA_URI_WITH_PARAM),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_UNTIL),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_SKIPPED));
List mediaPlaylists =
runPlaylistTrackerAndCollectMediaPlaylists(
new DefaultHttpDataSource.Factory(),
- Uri.parse(mockWebServer.url("/master.m3u8").toString()),
+ Uri.parse(mockWebServer.url("/multivariant.m3u8").toString()),
/* awaitedMediaPlaylistCount= */ 2);
assertRequestUrlsCalled(httpUrls);
@@ -257,16 +258,16 @@ public class DefaultHlsPlaylistTrackerTest {
List httpUrls =
enqueueWebServerResponses(
new String[] {
- "/master.m3u8", "/media0/playlist.m3u8", "/media0/playlist.m3u8?_HLS_msn=14"
+ "/multivariant.m3u8", "/media0/playlist.m3u8", "/media0/playlist.m3u8?_HLS_msn=14"
},
- getMockResponse(SAMPLE_M3U8_LIVE_MASTER),
+ getMockResponse(SAMPLE_M3U8_LIVE_MULTIVARIANT),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_BLOCK_RELOAD),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_BLOCK_RELOAD_NEXT));
List mediaPlaylists =
runPlaylistTrackerAndCollectMediaPlaylists(
new DefaultHttpDataSource.Factory(),
- Uri.parse(mockWebServer.url("/master.m3u8").toString()),
+ Uri.parse(mockWebServer.url("/multivariant.m3u8").toString()),
/* awaitedMediaPlaylistCount= */ 2);
assertRequestUrlsCalled(httpUrls);
@@ -281,18 +282,18 @@ public class DefaultHlsPlaylistTrackerTest {
List httpUrls =
enqueueWebServerResponses(
new String[] {
- "/master.m3u8",
+ "/multivariant.m3u8",
"/media0/playlist.m3u8",
"/media0/playlist.m3u8?_HLS_msn=14&_HLS_part=1"
},
- getMockResponse(SAMPLE_M3U8_LIVE_MASTER),
+ getMockResponse(SAMPLE_M3U8_LIVE_MULTIVARIANT),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_BLOCK_RELOAD_LOW_LATENCY),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_BLOCK_RELOAD_LOW_LATENCY_NEXT));
List mediaPlaylists =
runPlaylistTrackerAndCollectMediaPlaylists(
new DefaultHttpDataSource.Factory(),
- Uri.parse(mockWebServer.url("/master.m3u8").toString()),
+ Uri.parse(mockWebServer.url("/multivariant.m3u8").toString()),
/* awaitedMediaPlaylistCount= */ 2);
assertRequestUrlsCalled(httpUrls);
@@ -310,18 +311,18 @@ public class DefaultHlsPlaylistTrackerTest {
List httpUrls =
enqueueWebServerResponses(
new String[] {
- "/master.m3u8",
+ "/multivariant.m3u8",
"/media0/playlist.m3u8",
"/media0/playlist.m3u8?_HLS_msn=14&_HLS_part=0"
},
- getMockResponse(SAMPLE_M3U8_LIVE_MASTER),
+ getMockResponse(SAMPLE_M3U8_LIVE_MULTIVARIANT),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_BLOCK_RELOAD_LOW_LATENCY_FULL_SEGMENT),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_BLOCK_RELOAD_LOW_LATENCY_FULL_SEGMENT_NEXT));
List mediaPlaylists =
runPlaylistTrackerAndCollectMediaPlaylists(
new DefaultHttpDataSource.Factory(),
- Uri.parse(mockWebServer.url("/master.m3u8").toString()),
+ Uri.parse(mockWebServer.url("/multivariant.m3u8").toString()),
/* awaitedMediaPlaylistCount= */ 2);
assertRequestUrlsCalled(httpUrls);
@@ -339,11 +340,11 @@ public class DefaultHlsPlaylistTrackerTest {
List httpUrls =
enqueueWebServerResponses(
new String[] {
- "/master.m3u8",
+ "/multivariant.m3u8",
"/media0/playlist.m3u8",
"/media0/playlist.m3u8?_HLS_msn=14&_HLS_part=0"
},
- getMockResponse(SAMPLE_M3U8_LIVE_MASTER),
+ getMockResponse(SAMPLE_M3U8_LIVE_MULTIVARIANT),
getMockResponse(
SAMPLE_M3U8_LIVE_MEDIA_CAN_BLOCK_RELOAD_LOW_LATENCY_FULL_SEGMENT_PRELOAD),
getMockResponse(
@@ -352,7 +353,7 @@ public class DefaultHlsPlaylistTrackerTest {
List mediaPlaylists =
runPlaylistTrackerAndCollectMediaPlaylists(
new DefaultHttpDataSource.Factory(),
- Uri.parse(mockWebServer.url("/master.m3u8").toString()),
+ Uri.parse(mockWebServer.url("/multivariant.m3u8").toString()),
/* awaitedMediaPlaylistCount= */ 2);
assertRequestUrlsCalled(httpUrls);
@@ -370,13 +371,13 @@ public class DefaultHlsPlaylistTrackerTest {
List httpUrls =
enqueueWebServerResponses(
new String[] {
- "/master.m3u8",
+ "/multivariant.m3u8",
"/media0/playlist.m3u8",
"/media0/playlist.m3u8?_HLS_msn=16&_HLS_skip=YES",
"/media0/playlist.m3u8",
"/media0/playlist.m3u8?_HLS_msn=17&_HLS_skip=YES"
},
- getMockResponse(SAMPLE_M3U8_LIVE_MASTER),
+ getMockResponse(SAMPLE_M3U8_LIVE_MULTIVARIANT),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_UNTIL_AND_BLOCK_RELOAD),
new MockResponse().setResponseCode(400),
getMockResponse(SAMPLE_M3U8_LIVE_MEDIA_CAN_SKIP_UNTIL_AND_BLOCK_RELOAD_NEXT),
@@ -385,7 +386,7 @@ public class DefaultHlsPlaylistTrackerTest {
List mediaPlaylists =
runPlaylistTrackerAndCollectMediaPlaylists(
/* dataSourceFactory= */ new DefaultHttpDataSource.Factory(),
- Uri.parse(mockWebServer.url("/master.m3u8").toString()),
+ Uri.parse(mockWebServer.url("/multivariant.m3u8").toString()),
/* awaitedMediaPlaylistCount= */ 3);
assertRequestUrlsCalled(httpUrls);
@@ -415,7 +416,9 @@ public class DefaultHlsPlaylistTrackerTest {
}
private static List runPlaylistTrackerAndCollectMediaPlaylists(
- DataSource.Factory dataSourceFactory, Uri masterPlaylistUri, int awaitedMediaPlaylistCount)
+ DataSource.Factory dataSourceFactory,
+ Uri multivariantPlaylistUri,
+ int awaitedMediaPlaylistCount)
throws TimeoutException {
DefaultHlsPlaylistTracker defaultHlsPlaylistTracker =
@@ -427,7 +430,7 @@ public class DefaultHlsPlaylistTrackerTest {
List mediaPlaylists = new ArrayList<>();
AtomicInteger playlistCounter = new AtomicInteger();
defaultHlsPlaylistTracker.start(
- masterPlaylistUri,
+ multivariantPlaylistUri,
new MediaSourceEventListener.EventDispatcher(),
mediaPlaylist -> {
mediaPlaylists.add(mediaPlaylist);
diff --git a/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/playlist/HlsMediaPlaylistParserTest.java b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/playlist/HlsMediaPlaylistParserTest.java
index 868ce1fa01..ddfbb908a3 100644
--- a/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/playlist/HlsMediaPlaylistParserTest.java
+++ b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/playlist/HlsMediaPlaylistParserTest.java
@@ -392,7 +392,7 @@ public class HlsMediaPlaylistParserTest {
HlsMediaPlaylist playlist =
(HlsMediaPlaylist)
- new HlsPlaylistParser(HlsMasterPlaylist.EMPTY, previousPlaylist)
+ new HlsPlaylistParser(HlsMultivariantPlaylist.EMPTY, previousPlaylist)
.parse(playlistUri, inputStream);
assertThat(playlist.segments).hasSize(3);
@@ -446,7 +446,7 @@ public class HlsMediaPlaylistParserTest {
HlsMediaPlaylist playlist =
(HlsMediaPlaylist)
- new HlsPlaylistParser(HlsMasterPlaylist.EMPTY, previousPlaylist)
+ new HlsPlaylistParser(HlsMultivariantPlaylist.EMPTY, previousPlaylist)
.parse(playlistUri, inputStream);
assertThat(playlist.segments).hasSize(2);
@@ -1363,7 +1363,7 @@ public class HlsMediaPlaylistParserTest {
}
@Test
- public void masterPlaylistAttributeInheritance() throws IOException {
+ public void multivariantPlaylistAttributeInheritance() throws IOException {
Uri playlistUri = Uri.parse("https://example.com/test3.m3u8");
String playlistString =
"#EXTM3U\n"
@@ -1386,8 +1386,8 @@ public class HlsMediaPlaylistParserTest {
assertThat(standalonePlaylist.hasIndependentSegments).isFalse();
inputStream.reset();
- HlsMasterPlaylist masterPlaylist =
- new HlsMasterPlaylist(
+ HlsMultivariantPlaylist multivariantPlaylist =
+ new HlsMultivariantPlaylist(
/* baseUri= */ "https://example.com/",
/* tags= */ Collections.emptyList(),
/* variants= */ Collections.emptyList(),
@@ -1402,7 +1402,7 @@ public class HlsMediaPlaylistParserTest {
/* sessionKeyDrmInitData= */ Collections.emptyList());
HlsMediaPlaylist playlistWithInheritance =
(HlsMediaPlaylist)
- new HlsPlaylistParser(masterPlaylist, /* previousMediaPlaylist= */ null)
+ new HlsPlaylistParser(multivariantPlaylist, /* previousMediaPlaylist= */ null)
.parse(playlistUri, inputStream);
assertThat(playlistWithInheritance.hasIndependentSegments).isTrue();
}
@@ -1450,8 +1450,8 @@ public class HlsMediaPlaylistParserTest {
InputStream inputStream = new ByteArrayInputStream(Util.getUtf8Bytes(playlistString));
HashMap variableDefinitions = new HashMap<>();
variableDefinitions.put("imported_base", "long_path");
- HlsMasterPlaylist masterPlaylist =
- new HlsMasterPlaylist(
+ HlsMultivariantPlaylist multivariantPlaylist =
+ new HlsMultivariantPlaylist(
/* baseUri= */ "",
/* tags= */ Collections.emptyList(),
/* variants= */ Collections.emptyList(),
@@ -1466,7 +1466,7 @@ public class HlsMediaPlaylistParserTest {
/* sessionKeyDrmInitData= */ Collections.emptyList());
HlsMediaPlaylist playlist =
(HlsMediaPlaylist)
- new HlsPlaylistParser(masterPlaylist, /* previousMediaPlaylist= */ null)
+ new HlsPlaylistParser(multivariantPlaylist, /* previousMediaPlaylist= */ null)
.parse(playlistUri, inputStream);
for (int i = 1; i <= 4; i++) {
assertThat(playlist.segments.get(i - 1).url).isEqualTo("long_path" + i + ".ts");
diff --git a/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/playlist/HlsMasterPlaylistParserTest.java b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/playlist/HlsMultivariantPlaylistParserTest.java
similarity index 82%
rename from libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/playlist/HlsMasterPlaylistParserTest.java
rename to libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/playlist/HlsMultivariantPlaylistParserTest.java
index 88e2c9db4d..4c0be49920 100644
--- a/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/playlist/HlsMasterPlaylistParserTest.java
+++ b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/playlist/HlsMultivariantPlaylistParserTest.java
@@ -25,7 +25,7 @@ import androidx.media3.common.Metadata;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.ParserException;
import androidx.media3.exoplayer.hls.HlsTrackMetadataEntry;
-import androidx.media3.exoplayer.hls.playlist.HlsMasterPlaylist.Variant;
+import androidx.media3.exoplayer.hls.playlist.HlsMultivariantPlaylist.Variant;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.base.Charsets;
import java.io.ByteArrayInputStream;
@@ -36,9 +36,9 @@ import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
-/** Test for {@link HlsMasterPlaylist}. */
+/** Test for {@link HlsMultivariantPlaylist}. */
@RunWith(AndroidJUnit4.class)
-public class HlsMasterPlaylistParserTest {
+public class HlsMultivariantPlaylistParserTest {
private static final String PLAYLIST_URI = "https://example.com/test.m3u8";
@@ -233,12 +233,13 @@ public class HlsMasterPlaylistParserTest {
+ "#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=1313400,RESOLUTION=1920x1080,CODECS=\"avc1.640028\",URI=\"iframe_1313400/index.m3u8\"\n";
@Test
- public void parseMasterPlaylist_withSimple_success() throws IOException {
- HlsMasterPlaylist masterPlaylist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_SIMPLE);
+ public void parseMultivariantPlaylist_withSimple_success() throws IOException {
+ HlsMultivariantPlaylist multivariantPlaylist =
+ parseMultivariantPlaylist(PLAYLIST_URI, PLAYLIST_SIMPLE);
- List variants = masterPlaylist.variants;
+ List variants = multivariantPlaylist.variants;
assertThat(variants).hasSize(5);
- assertThat(masterPlaylist.muxedCaptionFormats).isNull();
+ assertThat(multivariantPlaylist.muxedCaptionFormats).isNull();
assertThat(variants.get(0).format.bitrate).isEqualTo(1280000);
assertThat(variants.get(0).format.codecs).isEqualTo("mp4a.40.2,avc1.66.30");
@@ -274,20 +275,20 @@ public class HlsMasterPlaylistParserTest {
}
@Test
- public void parseMasterPlaylist_withAverageBandwidth_success() throws IOException {
- HlsMasterPlaylist masterPlaylist =
- parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_AVG_BANDWIDTH);
+ public void parseMultivariantPlaylist_withAverageBandwidth_success() throws IOException {
+ HlsMultivariantPlaylist multivariantPlaylist =
+ parseMultivariantPlaylist(PLAYLIST_URI, PLAYLIST_WITH_AVG_BANDWIDTH);
- List variants = masterPlaylist.variants;
+ List variants = multivariantPlaylist.variants;
assertThat(variants.get(0).format.bitrate).isEqualTo(1280000);
assertThat(variants.get(1).format.bitrate).isEqualTo(1280000);
}
@Test
- public void parseMasterPlaylist_withInvalidHeader_throwsException() throws IOException {
+ public void parseMultivariantPlaylist_withInvalidHeader_throwsException() throws IOException {
try {
- parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_INVALID_HEADER);
+ parseMultivariantPlaylist(PLAYLIST_URI, PLAYLIST_WITH_INVALID_HEADER);
fail("Expected exception not thrown.");
} catch (ParserException e) {
// Expected due to invalid header.
@@ -295,8 +296,8 @@ public class HlsMasterPlaylistParserTest {
}
@Test
- public void parseMasterPlaylist_withClosedCaption_success() throws IOException {
- HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_CC);
+ public void parseMultivariantPlaylist_withClosedCaption_success() throws IOException {
+ HlsMultivariantPlaylist playlist = parseMultivariantPlaylist(PLAYLIST_URI, PLAYLIST_WITH_CC);
assertThat(playlist.muxedCaptionFormats).hasSize(1);
Format closedCaptionFormat = playlist.muxedCaptionFormats.get(0);
assertThat(closedCaptionFormat.sampleMimeType).isEqualTo(MimeTypes.APPLICATION_CEA708);
@@ -305,10 +306,10 @@ public class HlsMasterPlaylistParserTest {
}
@Test
- public void parseMasterPlaylist_withChannelsAttribute_success() throws IOException {
- HlsMasterPlaylist playlist =
- parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_CHANNELS_ATTRIBUTE);
- List audios = playlist.audios;
+ public void parseMultivariantPlaylist_withChannelsAttribute_success() throws IOException {
+ HlsMultivariantPlaylist playlist =
+ parseMultivariantPlaylist(PLAYLIST_URI, PLAYLIST_WITH_CHANNELS_ATTRIBUTE);
+ List audios = playlist.audios;
assertThat(audios).hasSize(3);
assertThat(audios.get(0).format.channelCount).isEqualTo(6);
assertThat(audios.get(1).format.channelCount).isEqualTo(2);
@@ -316,14 +317,15 @@ public class HlsMasterPlaylistParserTest {
}
@Test
- public void parseMasterPlaylist_withoutClosedCaption_success() throws IOException {
- HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITHOUT_CC);
+ public void parseMultivariantPlaylist_withoutClosedCaption_success() throws IOException {
+ HlsMultivariantPlaylist playlist = parseMultivariantPlaylist(PLAYLIST_URI, PLAYLIST_WITHOUT_CC);
assertThat(playlist.muxedCaptionFormats).isEmpty();
}
@Test
- public void parseMasterPlaylist_withAudio_codecPropagated() throws IOException {
- HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_AUDIO_MEDIA_TAG);
+ public void parseMultivariantPlaylist_withAudio_codecPropagated() throws IOException {
+ HlsMultivariantPlaylist playlist =
+ parseMultivariantPlaylist(PLAYLIST_URI, PLAYLIST_WITH_AUDIO_MEDIA_TAG);
Format firstAudioFormat = playlist.audios.get(0).format;
assertThat(firstAudioFormat.codecs).isEqualTo("mp4a.40.2");
@@ -335,8 +337,9 @@ public class HlsMasterPlaylistParserTest {
}
@Test
- public void parseMasterPlaylist_withAudio_audioIdPropagated() throws IOException {
- HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_AUDIO_MEDIA_TAG);
+ public void parseMultivariantPlaylist_withAudio_audioIdPropagated() throws IOException {
+ HlsMultivariantPlaylist playlist =
+ parseMultivariantPlaylist(PLAYLIST_URI, PLAYLIST_WITH_AUDIO_MEDIA_TAG);
Format firstAudioFormat = playlist.audios.get(0).format;
assertThat(firstAudioFormat.id).isEqualTo("aud1:English");
@@ -346,16 +349,17 @@ public class HlsMasterPlaylistParserTest {
}
@Test
- public void parseMasterPlaylist_withCc_cCIdPropagated() throws IOException {
- HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_CC);
+ public void parseMultivariantPlaylist_withCc_cCIdPropagated() throws IOException {
+ HlsMultivariantPlaylist playlist = parseMultivariantPlaylist(PLAYLIST_URI, PLAYLIST_WITH_CC);
Format firstTextFormat = playlist.muxedCaptionFormats.get(0);
assertThat(firstTextFormat.id).isEqualTo("cc1:Eng");
}
@Test
- public void parseMasterPlaylist_withSubtitles_subtitlesIdPropagated() throws IOException {
- HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_SUBTITLES);
+ public void parseMultivariantPlaylist_withSubtitles_subtitlesIdPropagated() throws IOException {
+ HlsMultivariantPlaylist playlist =
+ parseMultivariantPlaylist(PLAYLIST_URI, PLAYLIST_WITH_SUBTITLES);
Format firstTextFormat = playlist.subtitles.get(0).format;
assertThat(firstTextFormat.id).isEqualTo("sub1:Eng");
@@ -363,39 +367,40 @@ public class HlsMasterPlaylistParserTest {
}
@Test
- public void parseMasterPlaylist_subtitlesWithoutUri_skipsSubtitles() throws IOException {
- HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_SUBTITLES_NO_URI);
+ public void parseMultivariantPlaylist_subtitlesWithoutUri_skipsSubtitles() throws IOException {
+ HlsMultivariantPlaylist playlist =
+ parseMultivariantPlaylist(PLAYLIST_URI, PLAYLIST_WITH_SUBTITLES_NO_URI);
assertThat(playlist.subtitles).isEmpty();
}
@Test
- public void parseMasterPlaylist_withIndependentSegments_hasNoIndenpendentSegments()
+ public void parseMultivariantPlaylist_withIndependentSegments_hasNoIndenpendentSegments()
throws IOException {
- HlsMasterPlaylist playlistWithIndependentSegments =
- parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_INDEPENDENT_SEGMENTS);
+ HlsMultivariantPlaylist playlistWithIndependentSegments =
+ parseMultivariantPlaylist(PLAYLIST_URI, PLAYLIST_WITH_INDEPENDENT_SEGMENTS);
assertThat(playlistWithIndependentSegments.hasIndependentSegments).isTrue();
- HlsMasterPlaylist playlistWithoutIndependentSegments =
- parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_SIMPLE);
+ HlsMultivariantPlaylist playlistWithoutIndependentSegments =
+ parseMultivariantPlaylist(PLAYLIST_URI, PLAYLIST_SIMPLE);
assertThat(playlistWithoutIndependentSegments.hasIndependentSegments).isFalse();
}
@Test
- public void parseMasterPlaylist_withVariableSubstitution_success() throws IOException {
- HlsMasterPlaylist playlistWithSubstitutions =
- parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_VARIABLE_SUBSTITUTION);
- HlsMasterPlaylist.Variant variant = playlistWithSubstitutions.variants.get(0);
+ public void parseMultivariantPlaylist_withVariableSubstitution_success() throws IOException {
+ HlsMultivariantPlaylist playlistWithSubstitutions =
+ parseMultivariantPlaylist(PLAYLIST_URI, PLAYLIST_WITH_VARIABLE_SUBSTITUTION);
+ HlsMultivariantPlaylist.Variant variant = playlistWithSubstitutions.variants.get(0);
assertThat(variant.format.codecs).isEqualTo("mp4a.40.5");
assertThat(variant.url)
.isEqualTo(Uri.parse("http://example.com/This/{$nested}/reference/shouldnt/work"));
}
@Test
- public void parseMasterPlaylist_withTtmlSubtitle() throws IOException {
- HlsMasterPlaylist playlistWithTtmlSubtitle =
- parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_TTML_SUBTITLE);
- HlsMasterPlaylist.Variant variant = playlistWithTtmlSubtitle.variants.get(0);
+ public void parseMultivariantPlaylist_withTtmlSubtitle() throws IOException {
+ HlsMultivariantPlaylist playlistWithTtmlSubtitle =
+ parseMultivariantPlaylist(PLAYLIST_URI, PLAYLIST_WITH_TTML_SUBTITLE);
+ HlsMultivariantPlaylist.Variant variant = playlistWithTtmlSubtitle.variants.get(0);
Format firstTextFormat = playlistWithTtmlSubtitle.subtitles.get(0).format;
assertThat(firstTextFormat.id).isEqualTo("sub1:English");
assertThat(firstTextFormat.containerMimeType).isEqualTo(MimeTypes.APPLICATION_M3U8);
@@ -404,9 +409,9 @@ public class HlsMasterPlaylistParserTest {
}
@Test
- public void parseMasterPlaylist_withMatchingStreamInfUrls_success() throws IOException {
- HlsMasterPlaylist playlist =
- parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_MATCHING_STREAM_INF_URLS);
+ public void parseMultivariantPlaylist_withMatchingStreamInfUrls_success() throws IOException {
+ HlsMultivariantPlaylist playlist =
+ parseMultivariantPlaylist(PLAYLIST_URI, PLAYLIST_WITH_MATCHING_STREAM_INF_URLS);
assertThat(playlist.variants).hasSize(4);
assertThat(playlist.variants.get(0).format.metadata)
.isEqualTo(
@@ -441,7 +446,8 @@ public class HlsMasterPlaylistParserTest {
@Test
public void testIFrameVariant() throws IOException {
- HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, PLAYLIST_WITH_IFRAME_VARIANTS);
+ HlsMultivariantPlaylist playlist =
+ parseMultivariantPlaylist(PLAYLIST_URI, PLAYLIST_WITH_IFRAME_VARIANTS);
assertThat(playlist.variants).hasSize(5);
for (int i = 0; i < 4; i++) {
assertThat(playlist.variants.get(i).format.roleFlags).isEqualTo(0);
@@ -472,11 +478,11 @@ public class HlsMasterPlaylistParserTest {
/* captionGroupId= */ "cc1");
}
- private static HlsMasterPlaylist parseMasterPlaylist(String uri, String playlistString)
- throws IOException {
+ private static HlsMultivariantPlaylist parseMultivariantPlaylist(
+ String uri, String playlistString) throws IOException {
Uri playlistUri = Uri.parse(uri);
ByteArrayInputStream inputStream =
new ByteArrayInputStream(playlistString.getBytes(Charsets.UTF_8));
- return (HlsMasterPlaylist) new HlsPlaylistParser().parse(playlistUri, inputStream);
+ return (HlsMultivariantPlaylist) new HlsPlaylistParser().parse(playlistUri, inputStream);
}
}
diff --git a/libraries/test_data/src/test/assets/media/m3u8/live_low_latency_master b/libraries/test_data/src/test/assets/media/m3u8/live_low_latency_multivariant
similarity index 100%
rename from libraries/test_data/src/test/assets/media/m3u8/live_low_latency_master
rename to libraries/test_data/src/test/assets/media/m3u8/live_low_latency_multivariant
diff --git a/libraries/test_data/src/test/assets/media/m3u8/live_low_latency_master_media_uri_with_param b/libraries/test_data/src/test/assets/media/m3u8/live_low_latency_multivariant_media_uri_with_param
similarity index 100%
rename from libraries/test_data/src/test/assets/media/m3u8/live_low_latency_master_media_uri_with_param
rename to libraries/test_data/src/test/assets/media/m3u8/live_low_latency_multivariant_media_uri_with_param