• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.media.metrics;
18 
19 import android.annotation.FloatRange;
20 import android.annotation.IntDef;
21 import android.annotation.IntRange;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.os.Bundle;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 
28 import java.lang.annotation.Retention;
29 import java.lang.annotation.RetentionPolicy;
30 import java.util.Objects;
31 
32 /**
33  * Playback track change event.
34  */
35 public final class TrackChangeEvent extends Event implements Parcelable {
36     /** The track is off. */
37     public static final int TRACK_STATE_OFF = 0;
38     /** The track is on. */
39     public static final int TRACK_STATE_ON = 1;
40 
41     /** Unknown track change reason. */
42     public static final int TRACK_CHANGE_REASON_UNKNOWN = 0;
43     /** Other track change reason. */
44     public static final int TRACK_CHANGE_REASON_OTHER = 1;
45     /** Track change reason for initial state. */
46     public static final int TRACK_CHANGE_REASON_INITIAL = 2;
47     /** Track change reason for manual changes. */
48     public static final int TRACK_CHANGE_REASON_MANUAL = 3;
49     /** Track change reason for adaptive changes. */
50     public static final int TRACK_CHANGE_REASON_ADAPTIVE = 4;
51 
52     /** Audio track. */
53     public static final int TRACK_TYPE_AUDIO = 0;
54     /** Video track. */
55     public static final int TRACK_TYPE_VIDEO = 1;
56     /** Text track. */
57     public static final int TRACK_TYPE_TEXT = 2;
58 
59     private final int mState;
60     private final int mReason;
61     private final @Nullable String mContainerMimeType;
62     private final @Nullable String mSampleMimeType;
63     private final @Nullable String mCodecName;
64     private final int mBitrate;
65     private final long mTimeSinceCreatedMillis;
66     private final int mType;
67     private final @Nullable String mLanguage;
68     private final @Nullable String mLanguageRegion;
69     private final int mChannelCount;
70     private final int mAudioSampleRate;
71     private final int mWidth;
72     private final int mHeight;
73     private final float mVideoFrameRate;
74 
75 
76 
77     /** @hide */
78     @IntDef(prefix = "TRACK_STATE_", value = {
79         TRACK_STATE_OFF,
80         TRACK_STATE_ON
81     })
82     @Retention(RetentionPolicy.SOURCE)
83     public @interface TrackState {}
84 
85     /** @hide */
86     @IntDef(prefix = "TRACK_CHANGE_REASON_", value = {
87         TRACK_CHANGE_REASON_UNKNOWN,
88         TRACK_CHANGE_REASON_OTHER,
89         TRACK_CHANGE_REASON_INITIAL,
90         TRACK_CHANGE_REASON_MANUAL,
91         TRACK_CHANGE_REASON_ADAPTIVE
92     })
93     @Retention(RetentionPolicy.SOURCE)
94     public @interface TrackChangeReason {}
95 
96     /** @hide */
97     @IntDef(prefix = "TRACK_TYPE_", value = {
98         TRACK_TYPE_AUDIO,
99         TRACK_TYPE_VIDEO,
100         TRACK_TYPE_TEXT
101     })
102     @Retention(RetentionPolicy.SOURCE)
103     public @interface TrackType {}
104 
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)105     private TrackChangeEvent(
106             int state,
107             int reason,
108             @Nullable String containerMimeType,
109             @Nullable String sampleMimeType,
110             @Nullable String codecName,
111             int bitrate,
112             long timeSinceCreatedMillis,
113             int type,
114             @Nullable String language,
115             @Nullable String languageRegion,
116             int channelCount,
117             int sampleRate,
118             int width,
119             int height,
120             float videoFrameRate,
121             @NonNull Bundle extras) {
122         this.mState = state;
123         this.mReason = reason;
124         this.mContainerMimeType = containerMimeType;
125         this.mSampleMimeType = sampleMimeType;
126         this.mCodecName = codecName;
127         this.mBitrate = bitrate;
128         this.mTimeSinceCreatedMillis = timeSinceCreatedMillis;
129         this.mType = type;
130         this.mLanguage = language;
131         this.mLanguageRegion = languageRegion;
132         this.mChannelCount = channelCount;
133         this.mAudioSampleRate = sampleRate;
134         this.mWidth = width;
135         this.mHeight = height;
136         this.mVideoFrameRate = videoFrameRate;
137         this.mMetricsBundle = extras.deepCopy();
138     }
139 
140     /**
141      * Gets track state.
142      */
143     @TrackState
getTrackState()144     public int getTrackState() {
145         return mState;
146     }
147 
148     /**
149      * Gets track change reason.
150      */
151     @TrackChangeReason
getTrackChangeReason()152     public int getTrackChangeReason() {
153         return mReason;
154     }
155 
156     /**
157      * Gets container MIME type.
158      */
getContainerMimeType()159     public @Nullable String getContainerMimeType() {
160         return mContainerMimeType;
161     }
162 
163     /**
164      * Gets the MIME type of the video/audio/text samples.
165      */
getSampleMimeType()166     public @Nullable String getSampleMimeType() {
167         return mSampleMimeType;
168     }
169 
170     /**
171      * Gets codec name.
172      */
getCodecName()173     public @Nullable String getCodecName() {
174         return mCodecName;
175     }
176 
177     /**
178      * Gets bitrate.
179      * @return the bitrate, or -1 if unknown.
180      */
181     @IntRange(from = -1, to = Integer.MAX_VALUE)
getBitrate()182     public int getBitrate() {
183         return mBitrate;
184     }
185 
186     /**
187      * Gets timestamp since the creation of the log session in milliseconds.
188      * @return the timestamp since the creation in milliseconds, or -1 if unknown.
189      * @see LogSessionId
190      * @see PlaybackSession
191      * @see RecordingSession
192      */
193     @Override
194     @IntRange(from = -1)
getTimeSinceCreatedMillis()195     public long getTimeSinceCreatedMillis() {
196         return mTimeSinceCreatedMillis;
197     }
198 
199     /**
200      * Gets the track type.
201      * <p>The track type must be one of {@link #TRACK_TYPE_AUDIO}, {@link #TRACK_TYPE_VIDEO},
202      * {@link #TRACK_TYPE_TEXT}.
203      */
204     @TrackType
getTrackType()205     public int getTrackType() {
206         return mType;
207     }
208 
209     /**
210      * Gets language code.
211      * @return a two-letter ISO 639-1 language code.
212      */
getLanguage()213     public @Nullable String getLanguage() {
214         return mLanguage;
215     }
216 
217 
218     /**
219      * Gets language region code.
220      * @return an IETF BCP 47 optional language region subtag based on a two-letter country code.
221      */
getLanguageRegion()222     public @Nullable String getLanguageRegion() {
223         return mLanguageRegion;
224     }
225 
226     /**
227      * Gets channel count.
228      * @return the channel count, or -1 if unknown.
229      */
230     @IntRange(from = -1, to = Integer.MAX_VALUE)
getChannelCount()231     public int getChannelCount() {
232         return mChannelCount;
233     }
234 
235     /**
236      * Gets audio sample rate.
237      * @return the sample rate, or -1 if unknown.
238      */
239     @IntRange(from = -1, to = Integer.MAX_VALUE)
getAudioSampleRate()240     public int getAudioSampleRate() {
241         return mAudioSampleRate;
242     }
243 
244     /**
245      * Gets video width.
246      * @return the video width, or -1 if unknown.
247      */
248     @IntRange(from = -1, to = Integer.MAX_VALUE)
getWidth()249     public int getWidth() {
250         return mWidth;
251     }
252 
253     /**
254      * Gets video height.
255      * @return the video height, or -1 if unknown.
256      */
257     @IntRange(from = -1, to = Integer.MAX_VALUE)
getHeight()258     public int getHeight() {
259         return mHeight;
260     }
261 
262     /**
263      * Gets video frame rate.
264      * @return the video frame rate, or -1 if unknown.
265      */
266     @FloatRange(from = -1, to = Float.MAX_VALUE)
getVideoFrameRate()267     public float getVideoFrameRate() {
268         return mVideoFrameRate;
269     }
270 
271     /**
272      * Gets metrics-related information that is not supported by dedicated methods.
273      * <p>It is intended to be used for backwards compatibility by the metrics infrastructure.
274      */
275     @Override
276     @NonNull
getMetricsBundle()277     public Bundle getMetricsBundle() {
278         return mMetricsBundle;
279     }
280 
281     @Override
writeToParcel(@onNull Parcel dest, int flags)282     public void writeToParcel(@NonNull Parcel dest, int flags) {
283         int flg = 0;
284         if (mContainerMimeType != null) flg |= 0x4;
285         if (mSampleMimeType != null) flg |= 0x8;
286         if (mCodecName != null) flg |= 0x10;
287         if (mLanguage != null) flg |= 0x100;
288         if (mLanguageRegion != null) flg |= 0x200;
289         dest.writeInt(flg);
290         dest.writeInt(mState);
291         dest.writeInt(mReason);
292         if (mContainerMimeType != null) dest.writeString(mContainerMimeType);
293         if (mSampleMimeType != null) dest.writeString(mSampleMimeType);
294         if (mCodecName != null) dest.writeString(mCodecName);
295         dest.writeInt(mBitrate);
296         dest.writeLong(mTimeSinceCreatedMillis);
297         dest.writeInt(mType);
298         if (mLanguage != null) dest.writeString(mLanguage);
299         if (mLanguageRegion != null) dest.writeString(mLanguageRegion);
300         dest.writeInt(mChannelCount);
301         dest.writeInt(mAudioSampleRate);
302         dest.writeInt(mWidth);
303         dest.writeInt(mHeight);
304         dest.writeFloat(mVideoFrameRate);
305         dest.writeBundle(mMetricsBundle);
306     }
307 
308     @Override
describeContents()309     public int describeContents() {
310         return 0;
311     }
312 
TrackChangeEvent(@onNull Parcel in)313     private TrackChangeEvent(@NonNull Parcel in) {
314         int flg = in.readInt();
315         int state = in.readInt();
316         int reason = in.readInt();
317         String containerMimeType = (flg & 0x4) == 0 ? null : in.readString();
318         String sampleMimeType = (flg & 0x8) == 0 ? null : in.readString();
319         String codecName = (flg & 0x10) == 0 ? null : in.readString();
320         int bitrate = in.readInt();
321         long timeSinceCreatedMillis = in.readLong();
322         int type = in.readInt();
323         String language = (flg & 0x100) == 0 ? null : in.readString();
324         String languageRegion = (flg & 0x200) == 0 ? null : in.readString();
325         int channelCount = in.readInt();
326         int sampleRate = in.readInt();
327         int width = in.readInt();
328         int height = in.readInt();
329         float videoFrameRate = in.readFloat();
330         Bundle extras = in.readBundle();
331 
332         this.mState = state;
333         this.mReason = reason;
334         this.mContainerMimeType = containerMimeType;
335         this.mSampleMimeType = sampleMimeType;
336         this.mCodecName = codecName;
337         this.mBitrate = bitrate;
338         this.mTimeSinceCreatedMillis = timeSinceCreatedMillis;
339         this.mType = type;
340         this.mLanguage = language;
341         this.mLanguageRegion = languageRegion;
342         this.mChannelCount = channelCount;
343         this.mAudioSampleRate = sampleRate;
344         this.mWidth = width;
345         this.mHeight = height;
346         this.mVideoFrameRate = videoFrameRate;
347         this.mMetricsBundle = extras;
348     }
349 
350     public static final @NonNull Parcelable.Creator<TrackChangeEvent> CREATOR =
351             new Parcelable.Creator<TrackChangeEvent>() {
352         @Override
353         public TrackChangeEvent[] newArray(int size) {
354             return new TrackChangeEvent[size];
355         }
356 
357         @Override
358         public TrackChangeEvent createFromParcel(@NonNull Parcel in) {
359             return new TrackChangeEvent(in);
360         }
361     };
362 
363     @Override
toString()364     public String toString() {
365         return "TrackChangeEvent { "
366                 + "state = " + mState + ", "
367                 + "reason = " + mReason + ", "
368                 + "containerMimeType = " + mContainerMimeType + ", "
369                 + "sampleMimeType = " + mSampleMimeType + ", "
370                 + "codecName = " + mCodecName + ", "
371                 + "bitrate = " + mBitrate + ", "
372                 + "timeSinceCreatedMillis = " + mTimeSinceCreatedMillis + ", "
373                 + "type = " + mType + ", "
374                 + "language = " + mLanguage + ", "
375                 + "languageRegion = " + mLanguageRegion + ", "
376                 + "channelCount = " + mChannelCount + ", "
377                 + "sampleRate = " + mAudioSampleRate + ", "
378                 + "width = " + mWidth + ", "
379                 + "height = " + mHeight + ", "
380                 + "videoFrameRate = " + mVideoFrameRate
381                 + " }";
382     }
383 
384     @Override
equals(@ullable Object o)385     public boolean equals(@Nullable Object o) {
386         if (this == o) return true;
387         if (o == null || getClass() != o.getClass()) return false;
388         TrackChangeEvent that = (TrackChangeEvent) o;
389         return mState == that.mState
390                 && mReason == that.mReason
391                 && Objects.equals(mContainerMimeType, that.mContainerMimeType)
392                 && Objects.equals(mSampleMimeType, that.mSampleMimeType)
393                 && Objects.equals(mCodecName, that.mCodecName)
394                 && mBitrate == that.mBitrate
395                 && mTimeSinceCreatedMillis == that.mTimeSinceCreatedMillis
396                 && mType == that.mType
397                 && Objects.equals(mLanguage, that.mLanguage)
398                 && Objects.equals(mLanguageRegion, that.mLanguageRegion)
399                 && mChannelCount == that.mChannelCount
400                 && mAudioSampleRate == that.mAudioSampleRate
401                 && mWidth == that.mWidth
402                 && mHeight == that.mHeight
403                 && mVideoFrameRate == that.mVideoFrameRate;
404     }
405 
406     @Override
hashCode()407     public int hashCode() {
408         return Objects.hash(mState, mReason, mContainerMimeType, mSampleMimeType, mCodecName,
409                 mBitrate, mTimeSinceCreatedMillis, mType, mLanguage, mLanguageRegion,
410                 mChannelCount, mAudioSampleRate, mWidth, mHeight, mVideoFrameRate);
411     }
412 
413     /**
414      * A builder for {@link TrackChangeEvent}
415      */
416     public static final class Builder {
417         // TODO: check track type for the setters.
418         private int mState = TRACK_STATE_OFF;
419         private int mReason = TRACK_CHANGE_REASON_UNKNOWN;
420         private @Nullable String mContainerMimeType;
421         private @Nullable String mSampleMimeType;
422         private @Nullable String mCodecName;
423         private int mBitrate = -1;
424         private long mTimeSinceCreatedMillis = -1;
425         private final int mType;
426         private @Nullable String mLanguage;
427         private @Nullable String mLanguageRegion;
428         private int mChannelCount = -1;
429         private int mAudioSampleRate = -1;
430         private int mWidth = -1;
431         private int mHeight = -1;
432         private float mVideoFrameRate = -1;
433         private Bundle mMetricsBundle = new Bundle();
434 
435         private long mBuilderFieldsSet = 0L;
436 
437         /**
438          * Creates a new Builder.
439          * @param type the track type. It must be one of {@link #TRACK_TYPE_AUDIO},
440          *             {@link #TRACK_TYPE_VIDEO}, {@link #TRACK_TYPE_TEXT}.
441          */
Builder(@rackType int type)442         public Builder(@TrackType int type) {
443             if (type != TRACK_TYPE_AUDIO && type != TRACK_TYPE_VIDEO && type != TRACK_TYPE_TEXT) {
444                 throw new IllegalArgumentException("track type must be one of TRACK_TYPE_AUDIO, "
445                     + "TRACK_TYPE_VIDEO, TRACK_TYPE_TEXT.");
446             }
447             mType = type;
448         }
449 
450         /**
451          * Sets track state.
452          */
setTrackState(@rackState int value)453         public @NonNull Builder setTrackState(@TrackState int value) {
454             checkNotUsed();
455             mBuilderFieldsSet |= 0x1;
456             mState = value;
457             return this;
458         }
459 
460         /**
461          * Sets track change reason.
462          */
setTrackChangeReason(@rackChangeReason int value)463         public @NonNull Builder setTrackChangeReason(@TrackChangeReason int value) {
464             checkNotUsed();
465             mBuilderFieldsSet |= 0x2;
466             mReason = value;
467             return this;
468         }
469 
470         /**
471          * Sets container MIME type.
472          */
setContainerMimeType(@onNull String value)473         public @NonNull Builder setContainerMimeType(@NonNull String value) {
474             checkNotUsed();
475             mBuilderFieldsSet |= 0x4;
476             mContainerMimeType = value;
477             return this;
478         }
479 
480         /**
481          * Sets the MIME type of the video/audio/text samples.
482          */
setSampleMimeType(@onNull String value)483         public @NonNull Builder setSampleMimeType(@NonNull String value) {
484             checkNotUsed();
485             mBuilderFieldsSet |= 0x8;
486             mSampleMimeType = value;
487             return this;
488         }
489 
490         /**
491          * Sets codec name.
492          */
setCodecName(@onNull String value)493         public @NonNull Builder setCodecName(@NonNull String value) {
494             checkNotUsed();
495             mBuilderFieldsSet |= 0x10;
496             mCodecName = value;
497             return this;
498         }
499 
500         /**
501          * Sets bitrate in bits per second.
502          * @param value the bitrate in bits per second. -1 indicates the value is unknown.
503          */
setBitrate(@ntRangefrom = -1, to = Integer.MAX_VALUE) int value)504         public @NonNull Builder setBitrate(@IntRange(from = -1, to = Integer.MAX_VALUE) int value) {
505             checkNotUsed();
506             mBuilderFieldsSet |= 0x20;
507             mBitrate = value;
508             return this;
509         }
510 
511         /**
512          * Sets timestamp since the creation in milliseconds.
513          * @param value the timestamp since the creation in milliseconds.
514          *              -1 indicates the value is unknown.
515          * @see #getTimeSinceCreatedMillis()
516          */
setTimeSinceCreatedMillis(@ntRangefrom = -1) long value)517         public @NonNull Builder setTimeSinceCreatedMillis(@IntRange(from = -1) long value) {
518             checkNotUsed();
519             mBuilderFieldsSet |= 0x40;
520             mTimeSinceCreatedMillis = value;
521             return this;
522         }
523 
524         /**
525          * Sets language code.
526          * @param value a two-letter ISO 639-1 language code.
527          */
setLanguage(@onNull String value)528         public @NonNull Builder setLanguage(@NonNull String value) {
529             checkNotUsed();
530             mBuilderFieldsSet |= 0x100;
531             mLanguage = value;
532             return this;
533         }
534 
535         /**
536          * Sets language region code.
537          * @param value an IETF BCP 47 optional language region subtag based on a two-letter country
538          *              code.
539          */
setLanguageRegion(@onNull String value)540         public @NonNull Builder setLanguageRegion(@NonNull String value) {
541             checkNotUsed();
542             mBuilderFieldsSet |= 0x200;
543             mLanguageRegion = value;
544             return this;
545         }
546 
547         /**
548          * Sets channel count.
549          * @param value the channel count. -1 indicates the value is unknown.
550          */
setChannelCount( @ntRangefrom = -1, to = Integer.MAX_VALUE) int value)551         public @NonNull Builder setChannelCount(
552                 @IntRange(from = -1, to = Integer.MAX_VALUE) int value) {
553             checkNotUsed();
554             mBuilderFieldsSet |= 0x400;
555             mChannelCount = value;
556             return this;
557         }
558 
559         /**
560          * Sets sample rate.
561          * @param value the sample rate. -1 indicates the value is unknown.
562          */
setAudioSampleRate( @ntRangefrom = -1, to = Integer.MAX_VALUE) int value)563         public @NonNull Builder setAudioSampleRate(
564                 @IntRange(from = -1, to = Integer.MAX_VALUE) int value) {
565             checkNotUsed();
566             mBuilderFieldsSet |= 0x800;
567             mAudioSampleRate = value;
568             return this;
569         }
570 
571         /**
572          * Sets video width.
573          * @param value the video width. -1 indicates the value is unknown.
574          */
setWidth(@ntRangefrom = -1, to = Integer.MAX_VALUE) int value)575         public @NonNull Builder setWidth(@IntRange(from = -1, to = Integer.MAX_VALUE) int value) {
576             checkNotUsed();
577             mBuilderFieldsSet |= 0x1000;
578             mWidth = value;
579             return this;
580         }
581 
582         /**
583          * Sets video height.
584          * @param value the video height. -1 indicates the value is unknown.
585          */
setHeight(@ntRangefrom = -1, to = Integer.MAX_VALUE) int value)586         public @NonNull Builder setHeight(@IntRange(from = -1, to = Integer.MAX_VALUE) int value) {
587             checkNotUsed();
588             mBuilderFieldsSet |= 0x2000;
589             mHeight = value;
590             return this;
591         }
592 
593         /**
594          * Sets video frame rate.
595          * @param value the video frame rate. -1 indicates the value is unknown.
596          */
setVideoFrameRate( @loatRangefrom = -1, to = Float.MAX_VALUE) float value)597         public @NonNull Builder setVideoFrameRate(
598                 @FloatRange(from = -1, to = Float.MAX_VALUE) float value) {
599             checkNotUsed();
600             mVideoFrameRate = value;
601             return this;
602         }
603 
604         /**
605          * Sets metrics-related information that is not supported by dedicated
606          * methods.
607          * <p>It is intended to be used for backwards compatibility by the
608          * metrics infrastructure.
609          */
setMetricsBundle(@onNull Bundle metricsBundle)610         public @NonNull Builder setMetricsBundle(@NonNull Bundle metricsBundle) {
611             mMetricsBundle = metricsBundle;
612             return this;
613         }
614 
615         /** Builds the instance. This builder should not be touched after calling this! */
build()616         public @NonNull TrackChangeEvent build() {
617             checkNotUsed();
618             mBuilderFieldsSet |= 0x4000; // Mark builder used
619 
620             TrackChangeEvent o = new TrackChangeEvent(
621                     mState,
622                     mReason,
623                     mContainerMimeType,
624                     mSampleMimeType,
625                     mCodecName,
626                     mBitrate,
627                     mTimeSinceCreatedMillis,
628                     mType,
629                     mLanguage,
630                     mLanguageRegion,
631                     mChannelCount,
632                     mAudioSampleRate,
633                     mWidth,
634                     mHeight,
635                     mVideoFrameRate,
636                     mMetricsBundle);
637             return o;
638         }
639 
checkNotUsed()640         private void checkNotUsed() {
641             if ((mBuilderFieldsSet & 0x4000) != 0) {
642                 throw new IllegalStateException(
643                         "This Builder should not be reused. Use a new Builder instance instead");
644             }
645         }
646     }
647 }
648