From 3ec462d1cf8c26c717236a4bb4a7bf9ab1fdc7cd Mon Sep 17 00:00:00 2001 From: rohks Date: Tue, 8 Aug 2023 16:09:07 +0000 Subject: [PATCH] Add field object type (ot) Added this CMCD-Object field to Common Media Client Data (CMCD) logging. #minor-release PiperOrigin-RevId: 554843305 --- RELEASENOTES.md | 3 +- .../exoplayer/upstream/CmcdConfiguration.java | 12 +- .../upstream/CmcdHeadersFactory.java | 136 +++++++++++++++--- .../dash/DefaultDashChunkSource.java | 6 +- .../dash/DefaultDashChunkSourceTest.java | 6 +- .../media3/exoplayer/hls/HlsChunkSource.java | 40 ++++-- .../media3/exoplayer/hls/HlsMediaChunk.java | 13 +- .../exoplayer/hls/HlsChunkSourceTest.java | 6 +- .../smoothstreaming/DefaultSsChunkSource.java | 3 +- .../DefaultSsChunkSourceTest.java | 6 +- 10 files changed, 190 insertions(+), 41 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 6a6836ad2e4..bcd1998a6ad 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -37,7 +37,8 @@ (([#33](https://github.com/androidx/media/issues/33)),([#9978](https://github.com/google/ExoPlayer/issues/9978))). * Add additional fields to Common Media Client Data (CMCD) logging: streaming format (sf), stream type (st), version (v), top birate (tb), - object duration (d) and measured throughput (mtp). + object duration (d), measured throughput (mtp) and object type(ot) + ([#8699](https://github.com/google/ExoPlayer/issues/8699)). * Rename `MimeTypes.TEXT_EXOPLAYER_CUES` to `MimeTypes.APPLICATION_MEDIA3_CUES`. * Add `PngExtractor` that sends and reads a whole png file into the the diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/upstream/CmcdConfiguration.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/upstream/CmcdConfiguration.java index c1c50f90877..99796d8ef05 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/upstream/CmcdConfiguration.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/upstream/CmcdConfiguration.java @@ -66,7 +66,8 @@ public final class CmcdConfiguration { KEY_VERSION, KEY_TOP_BITRATE, KEY_OBJECT_DURATION, - KEY_MEASURED_THROUGHPUT + KEY_MEASURED_THROUGHPUT, + KEY_OBJECT_TYPE }) @Documented @Target(TYPE_USE) @@ -90,6 +91,7 @@ public final class CmcdConfiguration { public static final String KEY_TOP_BITRATE = "tb"; public static final String KEY_OBJECT_DURATION = "d"; public static final String KEY_MEASURED_THROUGHPUT = "mtp"; + public static final String KEY_OBJECT_TYPE = "ot"; /** * Factory for {@link CmcdConfiguration} instances. @@ -291,4 +293,12 @@ public boolean isObjectDurationLoggingAllowed() { public boolean isMeasuredThroughputLoggingAllowed() { return requestConfig.isKeyAllowed(KEY_MEASURED_THROUGHPUT); } + + /** + * Returns whether logging object type is allowed based on the {@linkplain RequestConfig request + * configuration}. + */ + public boolean isObjectTypeLoggingAllowed() { + return requestConfig.isKeyAllowed(KEY_OBJECT_TYPE); + } } diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/upstream/CmcdHeadersFactory.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/upstream/CmcdHeadersFactory.java index 95216e41ee6..64f12cebcdc 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/upstream/CmcdHeadersFactory.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/upstream/CmcdHeadersFactory.java @@ -23,6 +23,8 @@ import androidx.annotation.Nullable; import androidx.annotation.StringDef; import androidx.media3.common.C; +import androidx.media3.common.C.TrackType; +import androidx.media3.common.MimeTypes; import androidx.media3.common.TrackGroup; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; @@ -45,6 +47,33 @@ @UnstableApi public final class CmcdHeadersFactory { + /** + * Retrieves the object type value from the given {@link ExoTrackSelection}. + * + * @param trackSelection The {@link ExoTrackSelection} from which to retrieve the object type. + * @return The object type value as a String if {@link TrackType} can be mapped to one of the + * object types specified by {@link ObjectType} annotation, or {@code null}. + * @throws IllegalArgumentException if the provided {@link ExoTrackSelection} is {@code null}. + */ + @Nullable + public static @ObjectType String getObjectType(ExoTrackSelection trackSelection) { + checkArgument(trackSelection != null); + @C.TrackType + int trackType = MimeTypes.getTrackType(trackSelection.getSelectedFormat().sampleMimeType); + if (trackType == C.TRACK_TYPE_UNKNOWN) { + trackType = MimeTypes.getTrackType(trackSelection.getSelectedFormat().containerMimeType); + } + + if (trackType == C.TRACK_TYPE_AUDIO) { + return OBJECT_TYPE_AUDIO_ONLY; + } else if (trackType == C.TRACK_TYPE_VIDEO) { + return OBJECT_TYPE_VIDEO_ONLY; + } else { + // Track type cannot be mapped to a known object type. + return null; + } + } + /** Indicates the streaming format used for media content. */ @Retention(RetentionPolicy.SOURCE) @StringDef({STREAMING_FORMAT_DASH, STREAMING_FORMAT_HLS, STREAMING_FORMAT_SS}) @@ -59,6 +88,18 @@ public final class CmcdHeadersFactory { @Target(TYPE_USE) public @interface StreamType {} + /** Indicates the media type of current object being requested. */ + @Retention(RetentionPolicy.SOURCE) + @StringDef({ + OBJECT_TYPE_INIT_SEGMENT, + OBJECT_TYPE_AUDIO_ONLY, + OBJECT_TYPE_VIDEO_ONLY, + OBJECT_TYPE_MUXED_AUDIO_AND_VIDEO + }) + @Documented + @Target(TYPE_USE) + public @interface ObjectType {} + /** Represents the Dynamic Adaptive Streaming over HTTP (DASH) format. */ public static final String STREAMING_FORMAT_DASH = "d"; @@ -74,12 +115,25 @@ public final class CmcdHeadersFactory { /** Represents the Live Streaming stream type. */ public static final String STREAM_TYPE_LIVE = "l"; + /** Represents the object type for an initialization segment in a media container. */ + public static final String OBJECT_TYPE_INIT_SEGMENT = "i"; + + /** Represents the object type for audio-only content in a media container. */ + public static final String OBJECT_TYPE_AUDIO_ONLY = "a"; + + /** Represents the object type for video-only content in a media container. */ + public static final String OBJECT_TYPE_VIDEO_ONLY = "v"; + + /** Represents the object type for muxed audio and video content in a media container. */ + public static final String OBJECT_TYPE_MUXED_AUDIO_AND_VIDEO = "av"; + private final CmcdConfiguration cmcdConfiguration; private final ExoTrackSelection trackSelection; private final long bufferedDurationUs; private final @StreamingFormat String streamingFormat; private final boolean isLive; private long chunkDurationUs; + private @Nullable @ObjectType String objectType; /** * Creates an instance. @@ -122,6 +176,18 @@ public CmcdHeadersFactory setChunkDurationUs(long chunkDurationUs) { return this; } + /** + * Sets the object type of the current object being requested. Must be one of the allowed object + * types specified by the {@link ObjectType} annotation. + * + *

Default is {@code null}. + */ + @CanIgnoreReturnValue + public CmcdHeadersFactory setObjectType(@Nullable @ObjectType String objectType) { + this.objectType = objectType; + return this; + } + /** Creates and returns a new {@link ImmutableMap} containing the CMCD HTTP request headers. */ public ImmutableMap<@CmcdConfiguration.HeaderKey String, String> createHttpRequestHeaders() { ImmutableMap<@CmcdConfiguration.HeaderKey String, String> customData = @@ -130,24 +196,30 @@ public CmcdHeadersFactory setChunkDurationUs(long chunkDurationUs) { CmcdObject.Builder cmcdObject = new CmcdObject.Builder().setCustomData(customData.get(CmcdConfiguration.KEY_CMCD_OBJECT)); - if (cmcdConfiguration.isBitrateLoggingAllowed()) { - cmcdObject.setBitrateKbps(bitrateKbps); - } - if (cmcdConfiguration.isTopBitrateLoggingAllowed()) { - TrackGroup trackGroup = trackSelection.getTrackGroup(); - int topBitrate = trackSelection.getSelectedFormat().bitrate; - for (int i = 0; i < trackGroup.length; i++) { - topBitrate = max(topBitrate, trackGroup.getFormat(i).bitrate); + if (!getIsInitSegment()) { + if (cmcdConfiguration.isBitrateLoggingAllowed()) { + cmcdObject.setBitrateKbps(bitrateKbps); + } + if (cmcdConfiguration.isTopBitrateLoggingAllowed()) { + TrackGroup trackGroup = trackSelection.getTrackGroup(); + int topBitrate = trackSelection.getSelectedFormat().bitrate; + for (int i = 0; i < trackGroup.length; i++) { + topBitrate = max(topBitrate, trackGroup.getFormat(i).bitrate); + } + cmcdObject.setTopBitrateKbps(Util.ceilDivide(topBitrate, 1000)); + } + if (cmcdConfiguration.isObjectDurationLoggingAllowed() && chunkDurationUs != C.TIME_UNSET) { + cmcdObject.setObjectDurationMs(chunkDurationUs / 1000); } - cmcdObject.setTopBitrateKbps(Util.ceilDivide(topBitrate, 1000)); } - if (cmcdConfiguration.isObjectDurationLoggingAllowed() && chunkDurationUs != C.TIME_UNSET) { - cmcdObject.setObjectDurationMs(chunkDurationUs / 1000); + + if (cmcdConfiguration.isObjectTypeLoggingAllowed()) { + cmcdObject.setObjectType(objectType); } CmcdRequest.Builder cmcdRequest = new CmcdRequest.Builder().setCustomData(customData.get(CmcdConfiguration.KEY_CMCD_REQUEST)); - if (cmcdConfiguration.isBufferLengthLoggingAllowed()) { + if (!getIsInitSegment() && cmcdConfiguration.isBufferLengthLoggingAllowed()) { cmcdRequest.setBufferLengthMs(bufferedDurationUs / 1000); } if (cmcdConfiguration.isMeasuredThroughputLoggingAllowed() @@ -186,6 +258,10 @@ public CmcdHeadersFactory setChunkDurationUs(long chunkDurationUs) { return httpRequestHeaders.buildOrThrow(); } + private boolean getIsInitSegment() { + return objectType != null && objectType.equals(OBJECT_TYPE_INIT_SEGMENT); + } + /** Keys whose values vary with the object being requested. Contains CMCD fields: {@code br}. */ private static final class CmcdObject { @@ -194,6 +270,7 @@ public static final class Builder { private int bitrateKbps; private int topBitrateKbps; private long objectDurationMs; + @Nullable private @ObjectType String objectType; @Nullable private String customData; /** Creates a new instance with default values. */ @@ -231,6 +308,13 @@ public Builder setObjectDurationMs(long objectDurationMs) { return this; } + /** Sets the {@link CmcdObject#objectType}. The default value is {@code null}. */ + @CanIgnoreReturnValue + public Builder setObjectType(@Nullable @ObjectType String objectType) { + this.objectType = objectType; + return this; + } + /** Sets the {@link CmcdObject#customData}. The default value is {@code null}. */ @CanIgnoreReturnValue public Builder setCustomData(@Nullable String customData) { @@ -268,6 +352,14 @@ public CmcdObject build() { */ public final long objectDurationMs; + /** + * The media type of the current object being requested , or {@code null} if unset. Must be one + * of the allowed object types specified by the {@link ObjectType} annotation. + * + *

If the object type being requested is unknown, then this key MUST NOT be used. + */ + @Nullable public final @ObjectType String objectType; + /** * Custom data where the values of the keys vary with the object being requested, or {@code * null} if unset. @@ -281,6 +373,7 @@ private CmcdObject(Builder builder) { this.bitrateKbps = builder.bitrateKbps; this.topBitrateKbps = builder.topBitrateKbps; this.objectDurationMs = builder.objectDurationMs; + this.objectType = builder.objectType; this.customData = builder.customData; } @@ -306,6 +399,10 @@ public void populateHttpRequestHeaders( Util.formatInvariant( "%s=%d,", CmcdConfiguration.KEY_OBJECT_DURATION, objectDurationMs)); } + if (!TextUtils.isEmpty(objectType)) { + headerValue.append( + Util.formatInvariant("%s=%s,", CmcdConfiguration.KEY_OBJECT_TYPE, objectType)); + } if (!TextUtils.isEmpty(customData)) { headerValue.append(Util.formatInvariant("%s,", customData)); } @@ -377,6 +474,10 @@ public CmcdRequest build() { * The buffer length in milliseconds associated with the media object being requested, or {@link * C#TIME_UNSET} if unset. * + *

This key SHOULD only be sent with an {@link CmcdObject#objectType} of {@link + * #OBJECT_TYPE_AUDIO_ONLY}, {@link #OBJECT_TYPE_VIDEO_ONLY} or {@link + * #OBJECT_TYPE_MUXED_AUDIO_AND_VIDEO}. + * *

This value MUST be rounded to the nearest 100 ms. */ public final long bufferLengthMs; @@ -531,15 +632,16 @@ public CmcdSession build() { @Nullable public final String sessionId; /** - * The streaming format that defines the current request. d = MPEG DASH, h = HTTP Live Streaming - * (HLS), s = Smooth Streaming and o = other. If the streaming format being requested is - * unknown, then this key MUST NOT be used. + * The streaming format that defines the current request , or {@code null} if unset. Must be one + * of the allowed streaming formats specified by the {@link StreamingFormat} annotation. + * + *

If the streaming format being requested is unknown, then this key MUST NOT be used. */ @Nullable public final @StreamingFormat String streamingFormat; /** - * Type of stream. v = all segments are available – e.g., VOD and l = segments become available - * over time – e.g., LIVE. + * Type of stream, or {@code null} if unset. Must be one of the allowed stream types specified + * by the {@link StreamType} annotation. */ @Nullable public final @StreamType String streamType; diff --git a/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/DefaultDashChunkSource.java b/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/DefaultDashChunkSource.java index aece24f7044..096f3d2269a 100644 --- a/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/DefaultDashChunkSource.java +++ b/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/DefaultDashChunkSource.java @@ -662,7 +662,9 @@ protected Chunk newInitializationChunk( ImmutableMap<@CmcdConfiguration.HeaderKey String, String> httpRequestHeaders = cmcdHeadersFactory == null ? ImmutableMap.of() - : cmcdHeadersFactory.createHttpRequestHeaders(); + : cmcdHeadersFactory + .setObjectType(CmcdHeadersFactory.OBJECT_TYPE_INIT_SEGMENT) + .createHttpRequestHeaders(); DataSpec dataSpec = DashUtil.buildDataSpec( representation, @@ -706,6 +708,7 @@ protected Chunk newMediaChunk( ? ImmutableMap.of() : cmcdHeadersFactory .setChunkDurationUs(endTimeUs - startTimeUs) + .setObjectType(CmcdHeadersFactory.getObjectType(trackSelection)) .createHttpRequestHeaders(); DataSpec dataSpec = DashUtil.buildDataSpec( @@ -755,6 +758,7 @@ protected Chunk newMediaChunk( ? ImmutableMap.of() : cmcdHeadersFactory .setChunkDurationUs(endTimeUs - startTimeUs) + .setObjectType(CmcdHeadersFactory.getObjectType(trackSelection)) .createHttpRequestHeaders(); DataSpec dataSpec = DashUtil.buildDataSpec( diff --git a/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/DefaultDashChunkSourceTest.java b/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/DefaultDashChunkSourceTest.java index bd913aa183f..c19432cd38a 100644 --- a/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/DefaultDashChunkSourceTest.java +++ b/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/DefaultDashChunkSourceTest.java @@ -314,7 +314,7 @@ public void getNextChunk_chunkSourceWithDefaultCmcdConfiguration_setsCmcdLogging assertThat(output.chunk.dataSpec.httpRequestHeaders) .containsExactly( "CMCD-Object", - "br=700,tb=1300,d=4000", + "br=700,tb=1300,d=4000,ot=v", "CMCD-Request", "bl=0,mtp=1000", "CMCD-Session", @@ -359,7 +359,7 @@ public int getRequestedMaximumThroughputKbps(int throughputKbps) { assertThat(output.chunk.dataSpec.httpRequestHeaders) .containsExactly( "CMCD-Object", - "br=700,tb=1300,d=4000", + "br=700,tb=1300,d=4000,ot=v", "CMCD-Request", "bl=0,mtp=1000", "CMCD-Session", @@ -405,7 +405,7 @@ public int getRequestedMaximumThroughputKbps(int throughputKbps) { assertThat(output.chunk.dataSpec.httpRequestHeaders) .containsExactly( "CMCD-Object", - "br=700,tb=1300,d=4000,key1=value1", + "br=700,tb=1300,d=4000,ot=v,key1=value1", "CMCD-Request", "bl=0,mtp=1000,key2=\"stringValue\"", "CMCD-Session", diff --git a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsChunkSource.java b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsChunkSource.java index 0e399451820..73e3f398589 100644 --- a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsChunkSource.java +++ b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsChunkSource.java @@ -27,6 +27,7 @@ import androidx.annotation.VisibleForTesting; import androidx.media3.common.C; import androidx.media3.common.Format; +import androidx.media3.common.MimeTypes; import androidx.media3.common.TrackGroup; import androidx.media3.common.util.TimestampAdjuster; import androidx.media3.common.util.UriUtil; @@ -486,25 +487,31 @@ public void getNextChunk( cmcdConfiguration == null ? null : new CmcdHeadersFactory( - cmcdConfiguration, - trackSelection, - bufferedDurationUs, - /* streamingFormat= */ CmcdHeadersFactory.STREAMING_FORMAT_HLS, - /* isLive= */ !playlist.hasEndTag); + cmcdConfiguration, + trackSelection, + bufferedDurationUs, + /* streamingFormat= */ CmcdHeadersFactory.STREAMING_FORMAT_HLS, + /* isLive= */ !playlist.hasEndTag) + .setObjectType( + getIsMuxedAudioAndVideo() + ? CmcdHeadersFactory.OBJECT_TYPE_MUXED_AUDIO_AND_VIDEO + : CmcdHeadersFactory.getObjectType(trackSelection)); // Check if the media segment or its initialization segment are fully encrypted. @Nullable Uri initSegmentKeyUri = getFullEncryptionKeyUri(playlist, segmentBaseHolder.segmentBase.initializationSegment); out.chunk = - maybeCreateEncryptionChunkFor(initSegmentKeyUri, selectedTrackIndex, cmcdHeadersFactory); + maybeCreateEncryptionChunkFor( + initSegmentKeyUri, selectedTrackIndex, /* isInitSegment= */ true, cmcdHeadersFactory); if (out.chunk != null) { return; } @Nullable Uri mediaSegmentKeyUri = getFullEncryptionKeyUri(playlist, segmentBaseHolder.segmentBase); out.chunk = - maybeCreateEncryptionChunkFor(mediaSegmentKeyUri, selectedTrackIndex, cmcdHeadersFactory); + maybeCreateEncryptionChunkFor( + mediaSegmentKeyUri, selectedTrackIndex, /* isInitSegment= */ false, cmcdHeadersFactory); if (out.chunk != null) { return; } @@ -543,6 +550,13 @@ public void getNextChunk( cmcdHeadersFactory); } + private boolean getIsMuxedAudioAndVideo() { + Format format = trackGroup.getFormat(trackSelection.getSelectedIndex()); + String audioMimeType = MimeTypes.getAudioMediaMimeType(format.codecs); + String videoMimeType = MimeTypes.getVideoMediaMimeType(format.codecs); + return audioMimeType != null && videoMimeType != null; + } + @Nullable private static SegmentBaseHolder getNextSegmentHolder( HlsMediaPlaylist mediaPlaylist, long nextMediaSequence, int nextPartIndex) { @@ -850,6 +864,7 @@ private void updateLiveEdgeTimeUs(HlsMediaPlaylist mediaPlaylist) { private Chunk maybeCreateEncryptionChunkFor( @Nullable Uri keyUri, int selectedTrackIndex, + boolean isInitSegment, @Nullable CmcdHeadersFactory cmcdHeadersFactory) { if (keyUri == null) { return null; @@ -863,10 +878,15 @@ private Chunk maybeCreateEncryptionChunkFor( keyCache.put(keyUri, encryptionKey); return null; } + ImmutableMap<@CmcdConfiguration.HeaderKey String, String> httpRequestHeaders = - cmcdHeadersFactory == null - ? ImmutableMap.of() - : cmcdHeadersFactory.createHttpRequestHeaders(); + ImmutableMap.of(); + if (cmcdHeadersFactory != null) { + if (isInitSegment) { + cmcdHeadersFactory.setObjectType(CmcdHeadersFactory.OBJECT_TYPE_INIT_SEGMENT); + } + httpRequestHeaders = cmcdHeadersFactory.createHttpRequestHeaders(); + } DataSpec dataSpec = new DataSpec.Builder() .setUri(keyUri) diff --git a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsMediaChunk.java b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsMediaChunk.java index d10c3014fc0..182b684c995 100644 --- a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsMediaChunk.java +++ b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/HlsMediaChunk.java @@ -141,8 +141,19 @@ public static HlsMediaChunk createInstance( ? getEncryptionIvArray(Assertions.checkNotNull(initSegment.encryptionIV)) : null; Uri initSegmentUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, initSegment.url); + ImmutableMap<@CmcdConfiguration.HeaderKey String, String> initHttpRequestHeaders = + cmcdHeadersFactory == null + ? ImmutableMap.of() + : cmcdHeadersFactory + .setObjectType(CmcdHeadersFactory.OBJECT_TYPE_INIT_SEGMENT) + .createHttpRequestHeaders(); initDataSpec = - new DataSpec(initSegmentUri, initSegment.byteRangeOffset, initSegment.byteRangeLength); + new DataSpec.Builder() + .setUri(initSegmentUri) + .setPosition(initSegment.byteRangeOffset) + .setLength(initSegment.byteRangeLength) + .setHttpRequestHeaders(initHttpRequestHeaders) + .build(); initDataSource = buildDataSource(dataSource, initSegmentKey, initSegmentIv); } diff --git a/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/HlsChunkSourceTest.java b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/HlsChunkSourceTest.java index aad5789ff22..0a317d2042f 100644 --- a/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/HlsChunkSourceTest.java +++ b/libraries/exoplayer_hls/src/test/java/androidx/media3/exoplayer/hls/HlsChunkSourceTest.java @@ -210,7 +210,7 @@ public void getNextChunk_chunkSourceWithDefaultCmcdConfiguration_setsCmcdLogging assertThat(output.chunk.dataSpec.httpRequestHeaders) .containsExactly( "CMCD-Object", - "br=800,tb=800,d=4000", + "br=800,tb=800,d=4000,ot=v", "CMCD-Request", "bl=0", "CMCD-Session", @@ -256,7 +256,7 @@ public int getRequestedMaximumThroughputKbps(int throughputKbps) { assertThat(output.chunk.dataSpec.httpRequestHeaders) .containsExactly( "CMCD-Object", - "br=800,tb=800,d=4000", + "br=800,tb=800,d=4000,ot=v", "CMCD-Request", "bl=0", "CMCD-Session", @@ -303,7 +303,7 @@ public int getRequestedMaximumThroughputKbps(int throughputKbps) { assertThat(output.chunk.dataSpec.httpRequestHeaders) .containsExactly( "CMCD-Object", - "br=800,tb=800,d=4000,key1=value1", + "br=800,tb=800,d=4000,ot=v,key1=value1", "CMCD-Request", "bl=0,key2=\"stringValue\"", "CMCD-Session", diff --git a/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/DefaultSsChunkSource.java b/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/DefaultSsChunkSource.java index e508f2ecf40..e806c510ef8 100644 --- a/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/DefaultSsChunkSource.java +++ b/libraries/exoplayer_smoothstreaming/src/main/java/androidx/media3/exoplayer/smoothstreaming/DefaultSsChunkSource.java @@ -290,7 +290,8 @@ public final void getNextChunk( bufferedDurationUs, /* streamingFormat= */ CmcdHeadersFactory.STREAMING_FORMAT_SS, /* isLive= */ manifest.isLive) - .setChunkDurationUs(chunkEndTimeUs - chunkStartTimeUs); + .setChunkDurationUs(chunkEndTimeUs - chunkStartTimeUs) + .setObjectType(CmcdHeadersFactory.getObjectType(trackSelection)); out.chunk = newMediaChunk( diff --git a/libraries/exoplayer_smoothstreaming/src/test/java/androidx/media3/exoplayer/smoothstreaming/DefaultSsChunkSourceTest.java b/libraries/exoplayer_smoothstreaming/src/test/java/androidx/media3/exoplayer/smoothstreaming/DefaultSsChunkSourceTest.java index 82d25949755..a31784b5a9b 100644 --- a/libraries/exoplayer_smoothstreaming/src/test/java/androidx/media3/exoplayer/smoothstreaming/DefaultSsChunkSourceTest.java +++ b/libraries/exoplayer_smoothstreaming/src/test/java/androidx/media3/exoplayer/smoothstreaming/DefaultSsChunkSourceTest.java @@ -64,7 +64,7 @@ public void getNextChunk_chunkSourceWithDefaultCmcdConfiguration_setsCmcdLogging assertThat(output.chunk.dataSpec.httpRequestHeaders) .containsExactly( "CMCD-Object", - "br=308,tb=1536,d=1968", + "br=308,tb=1536,d=1968,ot=v", "CMCD-Request", "bl=0,mtp=1000", "CMCD-Session", @@ -109,7 +109,7 @@ public int getRequestedMaximumThroughputKbps(int throughputKbps) { assertThat(output.chunk.dataSpec.httpRequestHeaders) .containsExactly( "CMCD-Object", - "br=308,tb=1536,d=1968", + "br=308,tb=1536,d=1968,ot=v", "CMCD-Request", "bl=0,mtp=1000", "CMCD-Session", @@ -155,7 +155,7 @@ public int getRequestedMaximumThroughputKbps(int throughputKbps) { assertThat(output.chunk.dataSpec.httpRequestHeaders) .containsExactly( "CMCD-Object", - "br=308,tb=1536,d=1968,key1=value1", + "br=308,tb=1536,d=1968,ot=v,key1=value1", "CMCD-Request", "bl=0,mtp=1000,key2=\"stringValue\"", "CMCD-Session",