Set LogSessionId on MediaParser for HLS sources.

This requires some plumbing through HlsMediaPeriod and HlsChunkSource.

PiperOrigin-RevId: 411004283
This commit is contained in:
tonihei 2021-11-19 09:50:40 +00:00 committed by Ian Baker
parent 9af85d9b25
commit 0f766bc3d9
9 changed files with 76 additions and 25 deletions

View File

@ -27,6 +27,7 @@ import androidx.media3.common.Metadata;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.TimestampAdjuster;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.extractor.Extractor;
import androidx.media3.extractor.ExtractorInput;
import androidx.media3.extractor.mp3.Mp3Extractor;
@ -96,7 +97,8 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
@Nullable List<Format> muxedCaptionFormats,
TimestampAdjuster timestampAdjuster,
Map<String, List<String>> responseHeaders,
ExtractorInput sniffingExtractorInput)
ExtractorInput sniffingExtractorInput,
PlayerId playerId)
throws IOException {
@FileTypes.Type
int formatInferredFileType = FileTypes.inferFileTypeFromMimeType(format.sampleMimeType);

View File

@ -33,6 +33,7 @@ import androidx.media3.common.util.Util;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.DataSpec;
import androidx.media3.datasource.TransferListener;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.hls.playlist.HlsMediaPlaylist;
import androidx.media3.exoplayer.hls.playlist.HlsMediaPlaylist.Segment;
import androidx.media3.exoplayer.hls.playlist.HlsPlaylistTracker;
@ -122,6 +123,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final TrackGroup trackGroup;
@Nullable private final List<Format> muxedCaptionFormats;
private final FullSegmentEncryptionKeyCache keyCache;
private final PlayerId playerId;
private boolean isTimestampMaster;
private byte[] scratchSpace;
@ -161,13 +163,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
HlsDataSourceFactory dataSourceFactory,
@Nullable TransferListener mediaTransferListener,
TimestampAdjusterProvider timestampAdjusterProvider,
@Nullable List<Format> muxedCaptionFormats) {
@Nullable List<Format> muxedCaptionFormats,
PlayerId playerId) {
this.extractorFactory = extractorFactory;
this.playlistTracker = playlistTracker;
this.playlistUrls = playlistUrls;
this.playlistFormats = playlistFormats;
this.timestampAdjusterProvider = timestampAdjusterProvider;
this.muxedCaptionFormats = muxedCaptionFormats;
this.playerId = playerId;
keyCache = new FullSegmentEncryptionKeyCache(KEY_CACHE_SIZE);
scratchSpace = Util.EMPTY_BYTE_ARRAY;
liveEdgeInPeriodTimeUs = C.TIME_UNSET;
@ -453,7 +457,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
previous,
/* mediaSegmentKey= */ keyCache.get(mediaSegmentKeyUri),
/* initSegmentKey= */ keyCache.get(initSegmentKeyUri),
shouldSpliceIn);
shouldSpliceIn,
playerId);
}
@Nullable

View File

@ -20,6 +20,7 @@ import androidx.annotation.Nullable;
import androidx.media3.common.Format;
import androidx.media3.common.util.TimestampAdjuster;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.extractor.Extractor;
import androidx.media3.extractor.ExtractorInput;
import androidx.media3.extractor.PositionHolder;
@ -46,6 +47,7 @@ public interface HlsExtractorFactory {
* @param sniffingExtractorInput The first extractor input that will be passed to the returned
* extractor's {@link Extractor#read(ExtractorInput, PositionHolder)}. Must only be used to
* call {@link Extractor#sniff(ExtractorInput)}.
* @param playerId The {@link PlayerId} of the player using this extractors factory.
* @return An {@link HlsMediaChunkExtractor}.
* @throws IOException If an I/O error is encountered while sniffing.
*/
@ -55,6 +57,7 @@ public interface HlsExtractorFactory {
@Nullable List<Format> muxedCaptionFormats,
TimestampAdjuster timestampAdjuster,
Map<String, List<String>> responseHeaders,
ExtractorInput sniffingExtractorInput)
ExtractorInput sniffingExtractorInput,
PlayerId playerId)
throws IOException;
}

View File

@ -30,6 +30,7 @@ import androidx.media3.common.util.UriUtil;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.DataSourceUtil;
import androidx.media3.datasource.DataSpec;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.hls.playlist.HlsMediaPlaylist;
import androidx.media3.exoplayer.source.chunk.MediaChunk;
import androidx.media3.extractor.DefaultExtractorInput;
@ -91,7 +92,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
@Nullable HlsMediaChunk previousChunk,
@Nullable byte[] mediaSegmentKey,
@Nullable byte[] initSegmentKey,
boolean shouldSpliceIn) {
boolean shouldSpliceIn,
PlayerId playerId) {
// Media segment.
HlsMediaPlaylist.SegmentBase mediaSegment = segmentBaseHolder.segmentBase;
DataSpec dataSpec =
@ -184,7 +186,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
previousExtractor,
id3Decoder,
scratchId3Data,
shouldSpliceIn);
shouldSpliceIn,
playerId);
}
/**
@ -256,6 +259,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private final ParsableByteArray scratchId3Data;
private final boolean mediaSegmentEncrypted;
private final boolean initSegmentEncrypted;
private final PlayerId playerId;
private @MonotonicNonNull HlsMediaChunkExtractor extractor;
private @MonotonicNonNull HlsSampleStreamWrapper output;
@ -295,7 +299,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
@Nullable HlsMediaChunkExtractor previousExtractor,
Id3Decoder id3Decoder,
ParsableByteArray scratchId3Data,
boolean shouldSpliceIn) {
boolean shouldSpliceIn,
PlayerId playerId) {
super(
mediaDataSource,
dataSpec,
@ -324,6 +329,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
this.id3Decoder = id3Decoder;
this.scratchId3Data = scratchId3Data;
this.shouldSpliceIn = shouldSpliceIn;
this.playerId = playerId;
sampleQueueFirstSampleIndices = ImmutableList.of();
uid = uidSource.getAndIncrement();
}
@ -497,7 +503,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
muxedCaptionFormats,
timestampAdjuster,
dataSource.getResponseHeaders(),
extractorInput);
extractorInput,
playerId);
if (extractor.isPackedAudioExtractor()) {
output.setSampleOffsetUs(
id3Timestamp != C.TIME_UNSET

View File

@ -32,6 +32,7 @@ import androidx.media3.common.util.Util;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.TransferListener;
import androidx.media3.exoplayer.SeekParameters;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.drm.DrmSession;
import androidx.media3.exoplayer.drm.DrmSessionEventListener;
import androidx.media3.exoplayer.drm.DrmSessionManager;
@ -82,6 +83,7 @@ public final class HlsMediaPeriod
private final boolean allowChunklessPreparation;
private final @HlsMediaSource.MetadataType int metadataType;
private final boolean useSessionKeys;
private final PlayerId playerId;
@Nullable private Callback callback;
private int pendingPrepareCount;
@ -125,7 +127,8 @@ public final class HlsMediaPeriod
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
boolean allowChunklessPreparation,
@HlsMediaSource.MetadataType int metadataType,
boolean useSessionKeys) {
boolean useSessionKeys,
PlayerId playerId) {
this.extractorFactory = extractorFactory;
this.playlistTracker = playlistTracker;
this.dataSourceFactory = dataSourceFactory;
@ -139,6 +142,7 @@ public final class HlsMediaPeriod
this.allowChunklessPreparation = allowChunklessPreparation;
this.metadataType = metadataType;
this.useSessionKeys = useSessionKeys;
this.playerId = playerId;
compositeSequenceableLoader =
compositeSequenceableLoaderFactory.createCompositeSequenceableLoader();
streamWrapperIndices = new IdentityHashMap<>();
@ -773,7 +777,8 @@ public final class HlsMediaPeriod
dataSourceFactory,
mediaTransferListener,
timestampAdjusterProvider,
muxedCaptionFormats);
muxedCaptionFormats,
playerId);
return new HlsSampleStreamWrapper(
trackType,
/* callback= */ this,

View File

@ -499,7 +499,8 @@ public final class HlsMediaSource extends BaseMediaSource
compositeSequenceableLoaderFactory,
allowChunklessPreparation,
metadataType,
useSessionKeys);
useSessionKeys,
getPlayerId());
}
@Override

View File

@ -38,6 +38,8 @@ import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.source.mediaparser.InputReaderAdapterV30;
import androidx.media3.exoplayer.source.mediaparser.MediaParserUtil;
import androidx.media3.exoplayer.source.mediaparser.OutputConsumerAdapterV30;
@ -62,7 +64,8 @@ public final class MediaParserHlsMediaChunkExtractor implements HlsMediaChunkExt
muxedCaptionFormats,
timestampAdjuster,
responseHeaders,
sniffingExtractorInput) -> {
sniffingExtractorInput,
playerId) -> {
if (FileTypes.inferFileTypeFromMimeType(format.sampleMimeType) == FileTypes.WEBVTT) {
// The segment contains WebVTT. MediaParser does not support WebVTT parsing, so we use the
// bundled extractor.
@ -102,6 +105,7 @@ public final class MediaParserHlsMediaChunkExtractor implements HlsMediaChunkExt
format,
overrideInBandCaptionDeclarations,
muxedCaptionMediaFormats,
playerId,
MediaParser.PARSER_NAME_FMP4,
MediaParser.PARSER_NAME_AC3,
MediaParser.PARSER_NAME_AC4,
@ -121,7 +125,8 @@ public final class MediaParserHlsMediaChunkExtractor implements HlsMediaChunkExt
format,
overrideInBandCaptionDeclarations,
muxedCaptionMediaFormats,
/* leadingBytesToSkip= */ peekingInputReader.totalPeekedBytes);
/* leadingBytesToSkip= */ peekingInputReader.totalPeekedBytes,
playerId);
};
private final OutputConsumerAdapterV30 outputConsumerAdapter;
@ -130,6 +135,8 @@ public final class MediaParserHlsMediaChunkExtractor implements HlsMediaChunkExt
private final Format format;
private final boolean overrideInBandCaptionDeclarations;
private final ImmutableList<MediaFormat> muxedCaptionMediaFormats;
private final PlayerId playerId;
private int pendingSkipBytes;
/**
@ -148,6 +155,7 @@ public final class MediaParserHlsMediaChunkExtractor implements HlsMediaChunkExt
* that {@link MediaParser} should expose.
* @param leadingBytesToSkip The number of bytes to skip from the start of the input before
* starting extraction.
* @param playerId The {@link PlayerId} of the player using this chunk extractor.
*/
public MediaParserHlsMediaChunkExtractor(
MediaParser mediaParser,
@ -155,12 +163,14 @@ public final class MediaParserHlsMediaChunkExtractor implements HlsMediaChunkExt
Format format,
boolean overrideInBandCaptionDeclarations,
ImmutableList<MediaFormat> muxedCaptionMediaFormats,
int leadingBytesToSkip) {
int leadingBytesToSkip,
PlayerId playerId) {
this.mediaParser = mediaParser;
this.outputConsumerAdapter = outputConsumerAdapter;
this.overrideInBandCaptionDeclarations = overrideInBandCaptionDeclarations;
this.muxedCaptionMediaFormats = muxedCaptionMediaFormats;
this.format = format;
this.playerId = playerId;
pendingSkipBytes = leadingBytesToSkip;
inputReaderAdapter = new InputReaderAdapterV30();
}
@ -205,12 +215,14 @@ public final class MediaParserHlsMediaChunkExtractor implements HlsMediaChunkExt
format,
overrideInBandCaptionDeclarations,
muxedCaptionMediaFormats,
playerId,
mediaParser.getParserName()),
outputConsumerAdapter,
format,
overrideInBandCaptionDeclarations,
muxedCaptionMediaFormats,
/* leadingBytesToSkip= */ 0);
/* leadingBytesToSkip= */ 0,
playerId);
}
@Override
@ -225,6 +237,7 @@ public final class MediaParserHlsMediaChunkExtractor implements HlsMediaChunkExt
Format format,
boolean overrideInBandCaptionDeclarations,
ImmutableList<MediaFormat> muxedCaptionMediaFormats,
PlayerId playerId,
String... parserNames) {
MediaParser mediaParser =
parserNames.length == 1
@ -250,6 +263,9 @@ public final class MediaParserHlsMediaChunkExtractor implements HlsMediaChunkExt
mediaParser.setParameter(PARAMETER_TS_IGNORE_AVC_STREAM, true);
}
}
if (Util.SDK_INT >= 31) {
MediaParserUtil.setLogSessionIdOnMediaParser(mediaParser, playerId);
}
return mediaParser;
}

View File

@ -21,6 +21,7 @@ import android.net.Uri;
import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.TimestampAdjuster;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.extractor.DefaultExtractorsFactory;
import androidx.media3.extractor.ExtractorInput;
import androidx.media3.extractor.mp3.Mp3Extractor;
@ -79,7 +80,8 @@ public class DefaultHlsExtractorFactoryTest {
/* muxedCaptionFormats= */ null,
timestampAdjuster,
ac3ResponseHeaders,
webVttExtractorInput);
webVttExtractorInput,
PlayerId.UNSET);
assertThat(result.extractor.getClass()).isEqualTo(WebvttExtractor.class);
}
@ -103,7 +105,8 @@ public class DefaultHlsExtractorFactoryTest {
/* muxedCaptionFormats= */ null,
timestampAdjuster,
ac3ResponseHeaders,
ac3ExtractorInput);
ac3ExtractorInput,
PlayerId.UNSET);
assertThat(result.extractor.getClass()).isEqualTo(Ac3Extractor.class);
}
@ -125,7 +128,8 @@ public class DefaultHlsExtractorFactoryTest {
/* muxedCaptionFormats= */ null,
timestampAdjuster,
ac3ResponseHeaders,
tsExtractorInput);
tsExtractorInput,
PlayerId.UNSET);
assertThat(result.extractor.getClass()).isEqualTo(TsExtractor.class);
}
@ -148,7 +152,8 @@ public class DefaultHlsExtractorFactoryTest {
/* muxedCaptionFormats= */ null,
timestampAdjuster,
ac3ResponseHeaders,
mp3ExtractorInput);
mp3ExtractorInput,
PlayerId.UNSET);
assertThat(result.extractor.getClass()).isEqualTo(Mp3Extractor.class);
}
@ -170,7 +175,8 @@ public class DefaultHlsExtractorFactoryTest {
/* muxedCaptionFormats= */ null,
timestampAdjuster,
ImmutableMap.of("Content-Type", ImmutableList.of(MimeTypes.IMAGE_JPEG)),
tsExtractorInput);
tsExtractorInput,
PlayerId.UNSET);
assertThat(result.extractor.getClass()).isEqualTo(TsExtractor.class);
}
@ -187,7 +193,8 @@ public class DefaultHlsExtractorFactoryTest {
/* muxedCaptionFormats= */ null,
timestampAdjuster,
ac3ResponseHeaders,
emptyExtractorInput);
emptyExtractorInput,
PlayerId.UNSET);
// The format indicates WebVTT so we expect a WebVTT extractor.
assertThat(result.extractor.getClass()).isEqualTo(WebvttExtractor.class);
@ -205,7 +212,8 @@ public class DefaultHlsExtractorFactoryTest {
/* muxedCaptionFormats= */ null,
timestampAdjuster,
ac3ResponseHeaders,
emptyExtractorInput);
emptyExtractorInput,
PlayerId.UNSET);
// No format info, so we expect an AC-3 Extractor, as per HTTP Content-Type header.
assertThat(result.extractor.getClass()).isEqualTo(Ac3Extractor.class);
@ -223,7 +231,8 @@ public class DefaultHlsExtractorFactoryTest {
/* muxedCaptionFormats= */ null,
timestampAdjuster,
/* responseHeaders= */ ImmutableMap.of(),
emptyExtractorInput);
emptyExtractorInput,
PlayerId.UNSET);
// No format info, and no HTTP headers, so we expect an fMP4 extractor, as per file extension.
assertThat(result.extractor.getClass()).isEqualTo(FragmentedMp4Extractor.class);
@ -241,7 +250,8 @@ public class DefaultHlsExtractorFactoryTest {
/* muxedCaptionFormats= */ null,
timestampAdjuster,
/* responseHeaders= */ ImmutableMap.of(),
emptyExtractorInput);
emptyExtractorInput,
PlayerId.UNSET);
// There's no information for inferring the file type, we expect the factory to fall back on
// Transport Stream.

View File

@ -24,6 +24,7 @@ import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes;
import androidx.media3.datasource.DataSource;
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;
@ -92,7 +93,8 @@ public final class HlsMediaPeriodTest {
mock(CompositeSequenceableLoaderFactory.class),
/* allowChunklessPreparation= */ true,
HlsMediaSource.METADATA_TYPE_ID3,
/* useSessionKeys= */ false);
/* useSessionKeys= */ false,
PlayerId.UNSET);
};
MediaPeriodAsserts.assertGetStreamKeysAndManifestFilterIntegration(