diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java index 77f301a241..2f83f0c78b 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java @@ -22,6 +22,7 @@ import android.net.Uri; import android.text.TextUtils; import androidx.annotation.Nullable; import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.analytics.PlayerId; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor; @@ -94,7 +95,8 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory { @Nullable List muxedCaptionFormats, TimestampAdjuster timestampAdjuster, Map> responseHeaders, - ExtractorInput sniffingExtractorInput) + ExtractorInput sniffingExtractorInput, + PlayerId playerId) throws IOException { @FileTypes.Type int formatInferredFileType = FileTypes.inferFileTypeFromMimeType(format.sampleMimeType); diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java index fa1dfb48ad..85d70fa94f 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java @@ -26,6 +26,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.analytics.PlayerId; import com.google.android.exoplayer2.source.BehindLiveWindowException; import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.chunk.BaseMediaChunkIterator; @@ -122,6 +123,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; private final TrackGroup trackGroup; @Nullable private final List 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 muxedCaptionFormats) { + @Nullable List 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 diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsExtractorFactory.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsExtractorFactory.java index 4682ffa963..544f222c6a 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsExtractorFactory.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsExtractorFactory.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer2.source.hls; import android.net.Uri; import androidx.annotation.Nullable; import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.analytics.PlayerId; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.PositionHolder; @@ -44,6 +45,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. */ @@ -53,6 +55,7 @@ public interface HlsExtractorFactory { @Nullable List muxedCaptionFormats, TimestampAdjuster timestampAdjuster, Map> responseHeaders, - ExtractorInput sniffingExtractorInput) + ExtractorInput sniffingExtractorInput, + PlayerId playerId) throws IOException; } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java index 31a0a5096e..e405bfc374 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java @@ -21,6 +21,7 @@ import android.net.Uri; import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.analytics.PlayerId; import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.extractor.DefaultExtractorInput; import com.google.android.exoplayer2.extractor.ExtractorInput; @@ -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 diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java index 6e4430923e..252e15929f 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java @@ -21,6 +21,7 @@ import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.SeekParameters; +import com.google.android.exoplayer2.analytics.PlayerId; import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmSession; import com.google.android.exoplayer2.drm.DrmSessionEventListener; @@ -80,6 +81,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; @@ -123,7 +125,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; @@ -137,6 +140,7 @@ public final class HlsMediaPeriod this.allowChunklessPreparation = allowChunklessPreparation; this.metadataType = metadataType; this.useSessionKeys = useSessionKeys; + this.playerId = playerId; compositeSequenceableLoader = compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(); streamWrapperIndices = new IdentityHashMap<>(); @@ -771,7 +775,8 @@ public final class HlsMediaPeriod dataSourceFactory, mediaTransferListener, timestampAdjusterProvider, - muxedCaptionFormats); + muxedCaptionFormats, + playerId); return new HlsSampleStreamWrapper( trackType, /* callback= */ this, diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java index 501cf9ef01..0f85df5772 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java @@ -497,7 +497,8 @@ public final class HlsMediaSource extends BaseMediaSource compositeSequenceableLoaderFactory, allowChunklessPreparation, metadataType, - useSessionKeys); + useSessionKeys, + getPlayerId()); } @Override diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/MediaParserHlsMediaChunkExtractor.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/MediaParserHlsMediaChunkExtractor.java index 907d785f26..5b7956eb0d 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/MediaParserHlsMediaChunkExtractor.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/MediaParserHlsMediaChunkExtractor.java @@ -34,6 +34,7 @@ import android.text.TextUtils; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.analytics.PlayerId; import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.ExtractorOutput; import com.google.android.exoplayer2.source.mediaparser.InputReaderAdapterV30; @@ -42,6 +43,7 @@ import com.google.android.exoplayer2.source.mediaparser.OutputConsumerAdapterV30 import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.FileTypes; import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.Util; import com.google.common.collect.ImmutableList; import java.io.IOException; @@ -60,7 +62,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. @@ -100,6 +103,7 @@ public final class MediaParserHlsMediaChunkExtractor implements HlsMediaChunkExt format, overrideInBandCaptionDeclarations, muxedCaptionMediaFormats, + playerId, MediaParser.PARSER_NAME_FMP4, MediaParser.PARSER_NAME_AC3, MediaParser.PARSER_NAME_AC4, @@ -119,7 +123,8 @@ public final class MediaParserHlsMediaChunkExtractor implements HlsMediaChunkExt format, overrideInBandCaptionDeclarations, muxedCaptionMediaFormats, - /* leadingBytesToSkip= */ peekingInputReader.totalPeekedBytes); + /* leadingBytesToSkip= */ peekingInputReader.totalPeekedBytes, + playerId); }; private final OutputConsumerAdapterV30 outputConsumerAdapter; @@ -128,6 +133,8 @@ public final class MediaParserHlsMediaChunkExtractor implements HlsMediaChunkExt private final Format format; private final boolean overrideInBandCaptionDeclarations; private final ImmutableList muxedCaptionMediaFormats; + private final PlayerId playerId; + private int pendingSkipBytes; /** @@ -146,6 +153,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, @@ -153,12 +161,14 @@ public final class MediaParserHlsMediaChunkExtractor implements HlsMediaChunkExt Format format, boolean overrideInBandCaptionDeclarations, ImmutableList 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(); } @@ -203,12 +213,14 @@ public final class MediaParserHlsMediaChunkExtractor implements HlsMediaChunkExt format, overrideInBandCaptionDeclarations, muxedCaptionMediaFormats, + playerId, mediaParser.getParserName()), outputConsumerAdapter, format, overrideInBandCaptionDeclarations, muxedCaptionMediaFormats, - /* leadingBytesToSkip= */ 0); + /* leadingBytesToSkip= */ 0, + playerId); } @Override @@ -223,6 +235,7 @@ public final class MediaParserHlsMediaChunkExtractor implements HlsMediaChunkExt Format format, boolean overrideInBandCaptionDeclarations, ImmutableList muxedCaptionMediaFormats, + PlayerId playerId, String... parserNames) { MediaParser mediaParser = parserNames.length == 1 @@ -248,6 +261,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; } diff --git a/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactoryTest.java b/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactoryTest.java index 7055bc1ba4..0e8e5f8cd0 100644 --- a/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactoryTest.java +++ b/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactoryTest.java @@ -21,6 +21,7 @@ import android.net.Uri; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.analytics.PlayerId; import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.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. diff --git a/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriodTest.java b/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriodTest.java index 4ed8fc1ee3..39f59e7a33 100644 --- a/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriodTest.java +++ b/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriodTest.java @@ -22,6 +22,7 @@ import static org.mockito.Mockito.when; import android.net.Uri; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.analytics.PlayerId; import com.google.android.exoplayer2.drm.DrmSessionEventListener; import com.google.android.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory; @@ -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(