diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/CmcdConfiguration.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/CmcdConfiguration.java index e43c486acb1..a0ee67c73ae 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/CmcdConfiguration.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/CmcdConfiguration.java @@ -72,7 +72,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) @@ -96,6 +97,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. @@ -295,4 +297,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/library/core/src/main/java/com/google/android/exoplayer2/upstream/CmcdHeadersFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/CmcdHeadersFactory.java index 93955e1e899..cb38f4ca68f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/CmcdHeadersFactory.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/CmcdHeadersFactory.java @@ -23,8 +23,10 @@ import androidx.annotation.Nullable; import androidx.annotation.StringDef; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.C.TrackType; import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.trackselection.ExoTrackSelection; +import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; import com.google.common.collect.ImmutableMap; import com.google.errorprone.annotations.CanIgnoreReturnValue; @@ -49,6 +51,33 @@ @Deprecated 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}) @@ -63,6 +92,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"; @@ -78,12 +119,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. @@ -126,6 +180,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 = @@ -134,24 +200,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() @@ -190,6 +262,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 { @@ -198,6 +274,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. */ @@ -235,6 +312,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) { @@ -271,6 +355,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. @@ -284,6 +376,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; } @@ -309,6 +402,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)); } @@ -380,6 +477,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/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java index 52b91ab7602..f80025f2f9e 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java @@ -668,7 +668,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, @@ -712,6 +714,7 @@ protected Chunk newMediaChunk( ? ImmutableMap.of() : cmcdHeadersFactory .setChunkDurationUs(endTimeUs - startTimeUs) + .setObjectType(CmcdHeadersFactory.getObjectType(trackSelection)) .createHttpRequestHeaders(); DataSpec dataSpec = DashUtil.buildDataSpec( @@ -761,6 +764,7 @@ protected Chunk newMediaChunk( ? ImmutableMap.of() : cmcdHeadersFactory .setChunkDurationUs(endTimeUs - startTimeUs) + .setObjectType(CmcdHeadersFactory.getObjectType(trackSelection)) .createHttpRequestHeaders(); DataSpec dataSpec = DashUtil.buildDataSpec( diff --git a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSourceTest.java b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSourceTest.java index fe9a30d22d9..24558ea2874 100644 --- a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSourceTest.java +++ b/library/dash/src/test/java/com/google/android/exoplayer2/source/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/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 18c5fa20e1f..d1b0eb3b170 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 @@ -46,6 +46,7 @@ import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.TransferListener; +import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.TimestampAdjuster; import com.google.android.exoplayer2.util.UriUtil; import com.google.android.exoplayer2.util.Util; @@ -492,25 +493,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; } @@ -549,6 +556,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) { @@ -856,6 +870,7 @@ private void updateLiveEdgeTimeUs(HlsMediaPlaylist mediaPlaylist) { private Chunk maybeCreateEncryptionChunkFor( @Nullable Uri keyUri, int selectedTrackIndex, + boolean isInitSegment, @Nullable CmcdHeadersFactory cmcdHeadersFactory) { if (keyUri == null) { return null; @@ -869,10 +884,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/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 c414ffd2124..81f83b07a4b 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 @@ -149,8 +149,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/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsChunkSourceTest.java b/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsChunkSourceTest.java index 39bc3b4e61c..cc91712851e 100644 --- a/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsChunkSourceTest.java +++ b/library/hls/src/test/java/com/google/android/exoplayer2/source/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/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java index acbdbb548d7..57b447acb4c 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java @@ -296,7 +296,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/library/smoothstreaming/src/test/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSourceTest.java b/library/smoothstreaming/src/test/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSourceTest.java index b70793de3cf..f1dd84ba0c2 100644 --- a/library/smoothstreaming/src/test/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSourceTest.java +++ b/library/smoothstreaming/src/test/java/com/google/android/exoplayer2/source/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",