/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.media.metrics; import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** * Playback track change event. */ public final class TrackChangeEvent extends Event implements Parcelable { /** The track is off. */ public static final int TRACK_STATE_OFF = 0; /** The track is on. */ public static final int TRACK_STATE_ON = 1; /** Unknown track change reason. */ public static final int TRACK_CHANGE_REASON_UNKNOWN = 0; /** Other track change reason. */ public static final int TRACK_CHANGE_REASON_OTHER = 1; /** Track change reason for initial state. */ public static final int TRACK_CHANGE_REASON_INITIAL = 2; /** Track change reason for manual changes. */ public static final int TRACK_CHANGE_REASON_MANUAL = 3; /** Track change reason for adaptive changes. */ public static final int TRACK_CHANGE_REASON_ADAPTIVE = 4; /** Audio track. */ public static final int TRACK_TYPE_AUDIO = 0; /** Video track. */ public static final int TRACK_TYPE_VIDEO = 1; /** Text track. */ public static final int TRACK_TYPE_TEXT = 2; private final int mState; private final int mReason; private final @Nullable String mContainerMimeType; private final @Nullable String mSampleMimeType; private final @Nullable String mCodecName; private final int mBitrate; private final long mTimeSinceCreatedMillis; private final int mType; private final @Nullable String mLanguage; private final @Nullable String mLanguageRegion; private final int mChannelCount; private final int mAudioSampleRate; private final int mWidth; private final int mHeight; private final float mVideoFrameRate; /** @hide */ @IntDef(prefix = "TRACK_STATE_", value = { TRACK_STATE_OFF, TRACK_STATE_ON }) @Retention(RetentionPolicy.SOURCE) public @interface TrackState {} /** @hide */ @IntDef(prefix = "TRACK_CHANGE_REASON_", value = { TRACK_CHANGE_REASON_UNKNOWN, TRACK_CHANGE_REASON_OTHER, TRACK_CHANGE_REASON_INITIAL, TRACK_CHANGE_REASON_MANUAL, TRACK_CHANGE_REASON_ADAPTIVE }) @Retention(RetentionPolicy.SOURCE) public @interface TrackChangeReason {} /** @hide */ @IntDef(prefix = "TRACK_TYPE_", value = { TRACK_TYPE_AUDIO, TRACK_TYPE_VIDEO, TRACK_TYPE_TEXT }) @Retention(RetentionPolicy.SOURCE) public @interface TrackType {} private TrackChangeEvent( int state, int reason, @Nullable String containerMimeType, @Nullable String sampleMimeType, @Nullable String codecName, int bitrate, long timeSinceCreatedMillis, int type, @Nullable String language, @Nullable String languageRegion, int channelCount, int sampleRate, int width, int height, float videoFrameRate, @NonNull Bundle extras) { this.mState = state; this.mReason = reason; this.mContainerMimeType = containerMimeType; this.mSampleMimeType = sampleMimeType; this.mCodecName = codecName; this.mBitrate = bitrate; this.mTimeSinceCreatedMillis = timeSinceCreatedMillis; this.mType = type; this.mLanguage = language; this.mLanguageRegion = languageRegion; this.mChannelCount = channelCount; this.mAudioSampleRate = sampleRate; this.mWidth = width; this.mHeight = height; this.mVideoFrameRate = videoFrameRate; this.mMetricsBundle = extras.deepCopy(); } /** * Gets track state. */ @TrackState public int getTrackState() { return mState; } /** * Gets track change reason. */ @TrackChangeReason public int getTrackChangeReason() { return mReason; } /** * Gets container MIME type. */ public @Nullable String getContainerMimeType() { return mContainerMimeType; } /** * Gets the MIME type of the video/audio/text samples. */ public @Nullable String getSampleMimeType() { return mSampleMimeType; } /** * Gets codec name. */ public @Nullable String getCodecName() { return mCodecName; } /** * Gets bitrate. * @return the bitrate, or -1 if unknown. */ @IntRange(from = -1, to = Integer.MAX_VALUE) public int getBitrate() { return mBitrate; } /** * Gets timestamp since the creation of the log session in milliseconds. * @return the timestamp since the creation in milliseconds, or -1 if unknown. * @see LogSessionId * @see PlaybackSession * @see RecordingSession */ @Override @IntRange(from = -1) public long getTimeSinceCreatedMillis() { return mTimeSinceCreatedMillis; } /** * Gets the track type. *
The track type must be one of {@link #TRACK_TYPE_AUDIO}, {@link #TRACK_TYPE_VIDEO}, * {@link #TRACK_TYPE_TEXT}. */ @TrackType public int getTrackType() { return mType; } /** * Gets language code. * @return a two-letter ISO 639-1 language code. */ public @Nullable String getLanguage() { return mLanguage; } /** * Gets language region code. * @return an IETF BCP 47 optional language region subtag based on a two-letter country code. */ public @Nullable String getLanguageRegion() { return mLanguageRegion; } /** * Gets channel count. * @return the channel count, or -1 if unknown. */ @IntRange(from = -1, to = Integer.MAX_VALUE) public int getChannelCount() { return mChannelCount; } /** * Gets audio sample rate. * @return the sample rate, or -1 if unknown. */ @IntRange(from = -1, to = Integer.MAX_VALUE) public int getAudioSampleRate() { return mAudioSampleRate; } /** * Gets video width. * @return the video width, or -1 if unknown. */ @IntRange(from = -1, to = Integer.MAX_VALUE) public int getWidth() { return mWidth; } /** * Gets video height. * @return the video height, or -1 if unknown. */ @IntRange(from = -1, to = Integer.MAX_VALUE) public int getHeight() { return mHeight; } /** * Gets video frame rate. * @return the video frame rate, or -1 if unknown. */ @FloatRange(from = -1, to = Float.MAX_VALUE) public float getVideoFrameRate() { return mVideoFrameRate; } /** * Gets metrics-related information that is not supported by dedicated methods. *
It is intended to be used for backwards compatibility by the metrics infrastructure.
*/
@Override
@NonNull
public Bundle getMetricsBundle() {
return mMetricsBundle;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
int flg = 0;
if (mContainerMimeType != null) flg |= 0x4;
if (mSampleMimeType != null) flg |= 0x8;
if (mCodecName != null) flg |= 0x10;
if (mLanguage != null) flg |= 0x100;
if (mLanguageRegion != null) flg |= 0x200;
dest.writeInt(flg);
dest.writeInt(mState);
dest.writeInt(mReason);
if (mContainerMimeType != null) dest.writeString(mContainerMimeType);
if (mSampleMimeType != null) dest.writeString(mSampleMimeType);
if (mCodecName != null) dest.writeString(mCodecName);
dest.writeInt(mBitrate);
dest.writeLong(mTimeSinceCreatedMillis);
dest.writeInt(mType);
if (mLanguage != null) dest.writeString(mLanguage);
if (mLanguageRegion != null) dest.writeString(mLanguageRegion);
dest.writeInt(mChannelCount);
dest.writeInt(mAudioSampleRate);
dest.writeInt(mWidth);
dest.writeInt(mHeight);
dest.writeFloat(mVideoFrameRate);
dest.writeBundle(mMetricsBundle);
}
@Override
public int describeContents() {
return 0;
}
private TrackChangeEvent(@NonNull Parcel in) {
int flg = in.readInt();
int state = in.readInt();
int reason = in.readInt();
String containerMimeType = (flg & 0x4) == 0 ? null : in.readString();
String sampleMimeType = (flg & 0x8) == 0 ? null : in.readString();
String codecName = (flg & 0x10) == 0 ? null : in.readString();
int bitrate = in.readInt();
long timeSinceCreatedMillis = in.readLong();
int type = in.readInt();
String language = (flg & 0x100) == 0 ? null : in.readString();
String languageRegion = (flg & 0x200) == 0 ? null : in.readString();
int channelCount = in.readInt();
int sampleRate = in.readInt();
int width = in.readInt();
int height = in.readInt();
float videoFrameRate = in.readFloat();
Bundle extras = in.readBundle();
this.mState = state;
this.mReason = reason;
this.mContainerMimeType = containerMimeType;
this.mSampleMimeType = sampleMimeType;
this.mCodecName = codecName;
this.mBitrate = bitrate;
this.mTimeSinceCreatedMillis = timeSinceCreatedMillis;
this.mType = type;
this.mLanguage = language;
this.mLanguageRegion = languageRegion;
this.mChannelCount = channelCount;
this.mAudioSampleRate = sampleRate;
this.mWidth = width;
this.mHeight = height;
this.mVideoFrameRate = videoFrameRate;
this.mMetricsBundle = extras;
}
public static final @NonNull Parcelable.Creator It is intended to be used for backwards compatibility by the
* metrics infrastructure.
*/
public @NonNull Builder setMetricsBundle(@NonNull Bundle metricsBundle) {
mMetricsBundle = metricsBundle;
return this;
}
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull TrackChangeEvent build() {
checkNotUsed();
mBuilderFieldsSet |= 0x4000; // Mark builder used
TrackChangeEvent o = new TrackChangeEvent(
mState,
mReason,
mContainerMimeType,
mSampleMimeType,
mCodecName,
mBitrate,
mTimeSinceCreatedMillis,
mType,
mLanguage,
mLanguageRegion,
mChannelCount,
mAudioSampleRate,
mWidth,
mHeight,
mVideoFrameRate,
mMetricsBundle);
return o;
}
private void checkNotUsed() {
if ((mBuilderFieldsSet & 0x4000) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
}
}
}