Add fields streaming format(sf), stream type(st) and version(v)
Added these CMCD-Session fields to Common Media Client Data (CMCD) logging. #minor-release PiperOrigin-RevId: 547435498
This commit is contained in:
parent
bbdc64a732
commit
0412a36564
@ -32,6 +32,8 @@
|
||||
* Allow `MediaItem` updates for all `MediaSource` classes provided by the
|
||||
library via `Player.replaceMediaItem(s)`
|
||||
(([#33](https://github.com/androidx/media/issues/33)),([#9978](https://github.com/google/ExoPlayer/issues/9978))).
|
||||
* Add fields streaming format (sf), stream type (st) and version (v) to
|
||||
Common Media Client Data (CMCD) logging.
|
||||
* Transformer:
|
||||
* Parse EXIF rotation data for image inputs.
|
||||
* Remove `TransformationRequest.HdrMode` annotation type and its
|
||||
|
@ -60,7 +60,10 @@ public final class CmcdConfiguration {
|
||||
KEY_BUFFER_LENGTH,
|
||||
KEY_CONTENT_ID,
|
||||
KEY_SESSION_ID,
|
||||
KEY_MAXIMUM_REQUESTED_BITRATE
|
||||
KEY_MAXIMUM_REQUESTED_BITRATE,
|
||||
KEY_STREAMING_FORMAT,
|
||||
KEY_STREAM_TYPE,
|
||||
KEY_VERSION
|
||||
})
|
||||
@Documented
|
||||
@Target(TYPE_USE)
|
||||
@ -78,6 +81,9 @@ public final class CmcdConfiguration {
|
||||
public static final String KEY_CONTENT_ID = "cid";
|
||||
public static final String KEY_SESSION_ID = "sid";
|
||||
public static final String KEY_MAXIMUM_REQUESTED_BITRATE = "rtp";
|
||||
public static final String KEY_STREAMING_FORMAT = "sf";
|
||||
public static final String KEY_STREAM_TYPE = "st";
|
||||
public static final String KEY_VERSION = "v";
|
||||
|
||||
/**
|
||||
* Factory for {@link CmcdConfiguration} instances.
|
||||
@ -201,7 +207,7 @@ public final class CmcdConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether logging bitrate is allowed based on the {@linkplain RequestConfig request
|
||||
* Returns whether logging bitrate is allowed based on the {@linkplain RequestConfig request
|
||||
* configuration}.
|
||||
*/
|
||||
public boolean isBitrateLoggingAllowed() {
|
||||
@ -209,7 +215,7 @@ public final class CmcdConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether logging buffer length is allowed based on the {@linkplain RequestConfig request
|
||||
* Returns whether logging buffer length is allowed based on the {@linkplain RequestConfig request
|
||||
* configuration}.
|
||||
*/
|
||||
public boolean isBufferLengthLoggingAllowed() {
|
||||
@ -217,7 +223,7 @@ public final class CmcdConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether logging content ID is allowed based on the {@linkplain RequestConfig request
|
||||
* Returns whether logging content ID is allowed based on the {@linkplain RequestConfig request
|
||||
* configuration}.
|
||||
*/
|
||||
public boolean isContentIdLoggingAllowed() {
|
||||
@ -225,7 +231,7 @@ public final class CmcdConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether logging session ID is allowed based on the {@linkplain RequestConfig request
|
||||
* Returns whether logging session ID is allowed based on the {@linkplain RequestConfig request
|
||||
* configuration}.
|
||||
*/
|
||||
public boolean isSessionIdLoggingAllowed() {
|
||||
@ -233,10 +239,26 @@ public final class CmcdConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether logging maximum requested throughput is allowed based on the {@linkplain RequestConfig
|
||||
* request configuration}.
|
||||
* Returns whether logging maximum requested throughput is allowed based on the {@linkplain
|
||||
* RequestConfig request configuration}.
|
||||
*/
|
||||
public boolean isMaximumRequestThroughputLoggingAllowed() {
|
||||
return requestConfig.isKeyAllowed(KEY_MAXIMUM_REQUESTED_BITRATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether logging streaming format is allowed based on the {@linkplain RequestConfig
|
||||
* request configuration}.
|
||||
*/
|
||||
public boolean isStreamingFormatLoggingAllowed() {
|
||||
return requestConfig.isKeyAllowed(KEY_STREAMING_FORMAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether logging stream type is allowed based on the {@linkplain RequestConfig request
|
||||
* configuration}.
|
||||
*/
|
||||
public boolean isStreamTypeLoggingAllowed() {
|
||||
return requestConfig.isKeyAllowed(KEY_STREAM_TYPE);
|
||||
}
|
||||
}
|
||||
|
@ -16,15 +16,21 @@
|
||||
package androidx.media3.exoplayer.upstream;
|
||||
|
||||
import static androidx.media3.common.util.Assertions.checkArgument;
|
||||
import static java.lang.annotation.ElementType.TYPE_USE;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringDef;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.exoplayer.trackselection.ExoTrackSelection;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Represents the data for CMCD (Common Media Client Data) in adaptive streaming formats DASH, HLS,
|
||||
@ -37,6 +43,35 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||
@UnstableApi
|
||||
public final class CmcdLog {
|
||||
|
||||
/** Indicates the streaming format used for media content. */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@StringDef({STREAMING_FORMAT_DASH, STREAMING_FORMAT_HLS, STREAMING_FORMAT_SS})
|
||||
@Documented
|
||||
@Target(TYPE_USE)
|
||||
public @interface StreamingFormat {}
|
||||
|
||||
/** Indicates the type of streaming for media content. */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@StringDef({STREAM_TYPE_VOD, STREAM_TYPE_LIVE})
|
||||
@Documented
|
||||
@Target(TYPE_USE)
|
||||
public @interface StreamType {}
|
||||
|
||||
/** Represents the Dynamic Adaptive Streaming over HTTP (DASH) format. */
|
||||
public static final String STREAMING_FORMAT_DASH = "d";
|
||||
|
||||
/** Represents the HTTP Live Streaming (HLS) format. */
|
||||
public static final String STREAMING_FORMAT_HLS = "h";
|
||||
|
||||
/** Represents the Smooth Streaming (SS) format. */
|
||||
public static final String STREAMING_FORMAT_SS = "s";
|
||||
|
||||
/** Represents the Video on Demand (VOD) stream type. */
|
||||
public static final String STREAM_TYPE_VOD = "v";
|
||||
|
||||
/** Represents the Live Streaming stream type. */
|
||||
public static final String STREAM_TYPE_LIVE = "l";
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
@ -44,11 +79,17 @@ public final class CmcdLog {
|
||||
* @param trackSelection The {@linkplain ExoTrackSelection track selection}.
|
||||
* @param bufferedDurationUs The duration of media currently buffered from the current playback
|
||||
* position, in microseconds.
|
||||
* @param streamingFormat The streaming format of the media content. Must be one of the allowed
|
||||
* streaming formats specified by the {@link StreamingFormat} annotation.
|
||||
* @param isLive {@code true} if the media content is being streamed live, {@code false}
|
||||
* otherwise.
|
||||
*/
|
||||
public static CmcdLog createInstance(
|
||||
CmcdConfiguration cmcdConfiguration,
|
||||
ExoTrackSelection trackSelection,
|
||||
long bufferedDurationUs) {
|
||||
long bufferedDurationUs,
|
||||
@StreamingFormat String streamingFormat,
|
||||
boolean isLive) {
|
||||
ImmutableMap<@CmcdConfiguration.HeaderKey String, String> customData =
|
||||
cmcdConfiguration.requestConfig.getCustomData();
|
||||
int bitrateKbps = trackSelection.getSelectedFormat().bitrate / 1000;
|
||||
@ -76,6 +117,12 @@ public final class CmcdLog {
|
||||
if (cmcdConfiguration.isSessionIdLoggingAllowed()) {
|
||||
cmcdSession.setSessionId(cmcdConfiguration.sessionId);
|
||||
}
|
||||
if (cmcdConfiguration.isStreamingFormatLoggingAllowed()) {
|
||||
cmcdSession.setStreamingFormat(streamingFormat);
|
||||
}
|
||||
if (cmcdConfiguration.isStreamTypeLoggingAllowed()) {
|
||||
cmcdSession.setStreamType(isLive ? STREAM_TYPE_LIVE : STREAM_TYPE_VOD);
|
||||
}
|
||||
|
||||
CmcdLog.CmcdStatus.Builder cmcdStatus =
|
||||
new CmcdLog.CmcdStatus.Builder()
|
||||
@ -290,6 +337,8 @@ public final class CmcdLog {
|
||||
public static final class Builder {
|
||||
@Nullable private String contentId;
|
||||
@Nullable private String sessionId;
|
||||
@Nullable private String streamingFormat;
|
||||
@Nullable private String streamType;
|
||||
@Nullable private String customData;
|
||||
|
||||
/**
|
||||
@ -314,6 +363,20 @@ public final class CmcdLog {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the {@link CmcdSession#streamingFormat}. The default value is {@code null}. */
|
||||
@CanIgnoreReturnValue
|
||||
public Builder setStreamingFormat(@Nullable @StreamingFormat String streamingFormat) {
|
||||
this.streamingFormat = streamingFormat;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the {@link CmcdSession#streamType}. The default value is {@code null}. */
|
||||
@CanIgnoreReturnValue
|
||||
public Builder setStreamType(@Nullable @StreamType String streamType) {
|
||||
this.streamType = streamType;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Sets the {@link CmcdSession#customData}. The default value is {@code null}. */
|
||||
@CanIgnoreReturnValue
|
||||
public CmcdSession.Builder setCustomData(@Nullable String customData) {
|
||||
@ -326,6 +389,13 @@ public final class CmcdLog {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The version of this specification used for interpreting the defined key names and values. If
|
||||
* this key is omitted, the client and server MUST interpret the values as being defined by
|
||||
* version 1. Client SHOULD omit this field if the version is 1.
|
||||
*/
|
||||
public static final int VERSION = 1;
|
||||
|
||||
/**
|
||||
* A GUID identifying the current content, or {@code null} if unset.
|
||||
*
|
||||
@ -342,6 +412,19 @@ public final class CmcdLog {
|
||||
*/
|
||||
@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.
|
||||
*/
|
||||
@Nullable public final String streamingFormat;
|
||||
|
||||
/**
|
||||
* Type of stream. v = all segments are available – e.g., VOD and l = segments become available
|
||||
* over time – e.g., LIVE.
|
||||
*/
|
||||
@Nullable public final String streamType;
|
||||
|
||||
/**
|
||||
* Custom data where the values of the keys are expected to be invariant over the life of the
|
||||
* session, or {@code null} if unset.
|
||||
@ -354,6 +437,8 @@ public final class CmcdLog {
|
||||
private CmcdSession(Builder builder) {
|
||||
this.contentId = builder.contentId;
|
||||
this.sessionId = builder.sessionId;
|
||||
this.streamingFormat = builder.streamingFormat;
|
||||
this.streamType = builder.streamType;
|
||||
this.customData = builder.customData;
|
||||
}
|
||||
|
||||
@ -374,6 +459,18 @@ public final class CmcdLog {
|
||||
headerValue.append(
|
||||
Util.formatInvariant("%s=\"%s\",", CmcdConfiguration.KEY_SESSION_ID, sessionId));
|
||||
}
|
||||
if (!TextUtils.isEmpty(this.streamingFormat)) {
|
||||
headerValue.append(
|
||||
Util.formatInvariant(
|
||||
"%s=%s,", CmcdConfiguration.KEY_STREAMING_FORMAT, streamingFormat));
|
||||
}
|
||||
if (!TextUtils.isEmpty(this.streamType)) {
|
||||
headerValue.append(
|
||||
Util.formatInvariant("%s=%s,", CmcdConfiguration.KEY_STREAM_TYPE, streamType));
|
||||
}
|
||||
if (VERSION != 1) {
|
||||
headerValue.append(Util.formatInvariant("%s=%d,", CmcdConfiguration.KEY_VERSION, VERSION));
|
||||
}
|
||||
if (!TextUtils.isEmpty(customData)) {
|
||||
headerValue.append(Util.formatInvariant("%s,", customData));
|
||||
}
|
||||
|
@ -60,7 +60,11 @@ public class CmcdLogTest {
|
||||
.thenReturn(new Format.Builder().setPeakBitrate(840_000).build());
|
||||
CmcdLog cmcdLog =
|
||||
CmcdLog.createInstance(
|
||||
cmcdConfiguration, trackSelection, /* bufferedDurationUs= */ 1_760_000);
|
||||
cmcdConfiguration,
|
||||
trackSelection,
|
||||
/* bufferedDurationUs= */ 1_760_000,
|
||||
CmcdLog.STREAMING_FORMAT_DASH,
|
||||
true);
|
||||
|
||||
ImmutableMap<@CmcdConfiguration.HeaderKey String, String> requestHeaders =
|
||||
cmcdLog.getHttpRequestHeaders();
|
||||
@ -72,7 +76,7 @@ public class CmcdLogTest {
|
||||
"CMCD-Request",
|
||||
"bl=1800,key2=\"stringValue\"",
|
||||
"CMCD-Session",
|
||||
"cid=\"mediaId\",sid=\"sessionId\"",
|
||||
"cid=\"mediaId\",sid=\"sessionId\",sf=d,st=l",
|
||||
"CMCD-Status",
|
||||
"rtp=1700");
|
||||
}
|
||||
|
@ -374,7 +374,12 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
CmcdLog cmcdLog =
|
||||
cmcdConfiguration == null
|
||||
? null
|
||||
: CmcdLog.createInstance(cmcdConfiguration, trackSelection, bufferedDurationUs);
|
||||
: CmcdLog.createInstance(
|
||||
cmcdConfiguration,
|
||||
trackSelection,
|
||||
bufferedDurationUs,
|
||||
CmcdLog.STREAMING_FORMAT_DASH,
|
||||
manifest.dynamic);
|
||||
|
||||
RepresentationHolder representationHolder =
|
||||
updateSelectedBaseUrl(trackSelection.getSelectedIndex());
|
||||
|
@ -318,7 +318,7 @@ public class DefaultDashChunkSourceTest {
|
||||
"CMCD-Request",
|
||||
"bl=0",
|
||||
"CMCD-Session",
|
||||
"cid=\"mediaId\",sid=\"" + cmcdConfiguration.sessionId + "\"");
|
||||
"cid=\"mediaId\",sid=\"" + cmcdConfiguration.sessionId + "\",sf=d,st=v");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -363,7 +363,7 @@ public class DefaultDashChunkSourceTest {
|
||||
"CMCD-Request",
|
||||
"bl=0",
|
||||
"CMCD-Session",
|
||||
"cid=\"mediaIdcontentIdSuffix\"",
|
||||
"cid=\"mediaIdcontentIdSuffix\",sf=d,st=v",
|
||||
"CMCD-Status",
|
||||
"rtp=3500");
|
||||
}
|
||||
@ -409,7 +409,7 @@ public class DefaultDashChunkSourceTest {
|
||||
"CMCD-Request",
|
||||
"bl=0,key2=\"stringValue\"",
|
||||
"CMCD-Session",
|
||||
"cid=\"mediaId\",sid=\"" + cmcdConfiguration.sessionId + "\",key3=1",
|
||||
"cid=\"mediaId\",sid=\"" + cmcdConfiguration.sessionId + "\",sf=d,st=v,key3=1",
|
||||
"CMCD-Status",
|
||||
"key4=5.0");
|
||||
}
|
||||
|
@ -485,7 +485,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
CmcdLog cmcdLog =
|
||||
cmcdConfiguration == null
|
||||
? null
|
||||
: CmcdLog.createInstance(cmcdConfiguration, trackSelection, bufferedDurationUs);
|
||||
: CmcdLog.createInstance(
|
||||
cmcdConfiguration,
|
||||
trackSelection,
|
||||
bufferedDurationUs,
|
||||
CmcdLog.STREAMING_FORMAT_HLS,
|
||||
!playlist.hasEndTag);
|
||||
|
||||
// Check if the media segment or its initialization segment are fully encrypted.
|
||||
@Nullable
|
||||
|
@ -214,7 +214,7 @@ public class HlsChunkSourceTest {
|
||||
"CMCD-Request",
|
||||
"bl=0",
|
||||
"CMCD-Session",
|
||||
"cid=\"mediaId\",sid=\"" + cmcdConfiguration.sessionId + "\"");
|
||||
"cid=\"mediaId\",sid=\"" + cmcdConfiguration.sessionId + "\",sf=h,st=v");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -260,7 +260,7 @@ public class HlsChunkSourceTest {
|
||||
"CMCD-Request",
|
||||
"bl=0",
|
||||
"CMCD-Session",
|
||||
"cid=\"mediaIdcontentIdSuffix\"",
|
||||
"cid=\"mediaIdcontentIdSuffix\",sf=h,st=v",
|
||||
"CMCD-Status",
|
||||
"rtp=4000");
|
||||
}
|
||||
@ -307,7 +307,7 @@ public class HlsChunkSourceTest {
|
||||
"CMCD-Request",
|
||||
"bl=0,key2=\"stringValue\"",
|
||||
"CMCD-Session",
|
||||
"cid=\"mediaId\",sid=\"" + cmcdConfiguration.sessionId + "\",key3=1",
|
||||
"cid=\"mediaId\",sid=\"" + cmcdConfiguration.sessionId + "\",sf=h,st=v,key3=1",
|
||||
"CMCD-Status",
|
||||
"key4=5.0");
|
||||
}
|
||||
|
@ -284,7 +284,12 @@ public class DefaultSsChunkSource implements SsChunkSource {
|
||||
CmcdLog cmcdLog =
|
||||
cmcdConfiguration == null
|
||||
? null
|
||||
: CmcdLog.createInstance(cmcdConfiguration, trackSelection, bufferedDurationUs);
|
||||
: CmcdLog.createInstance(
|
||||
cmcdConfiguration,
|
||||
trackSelection,
|
||||
bufferedDurationUs,
|
||||
CmcdLog.STREAMING_FORMAT_SS,
|
||||
manifest.isLive);
|
||||
|
||||
out.chunk =
|
||||
newMediaChunk(
|
||||
|
Loading…
x
Reference in New Issue
Block a user