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.telephony.ims;
18 
19 import android.annotation.IntRange;
20 import android.annotation.NonNull;
21 import android.annotation.SystemApi;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 
25 import java.util.Arrays;
26 import java.util.Objects;
27 
28 /**
29  * A representation of an RTP header extension.
30  * <p>
31  * Per RFC8285, an RTP header extension consists of both a local identifier in the range 1-14, an
32  * 8-bit length indicator and a number of extension data bytes equivalent to the stated length.
33  * @hide
34  */
35 @SystemApi
36 public final class RtpHeaderExtension implements Parcelable {
37     private int mLocalIdentifier;
38     private byte[] mExtensionData;
39 
40     /**
41      * Creates a new {@link RtpHeaderExtension}.
42      * @param localIdentifier The local identifier for this RTP header extension.
43      * @param extensionData The data for this RTP header extension.
44      * @throws IllegalArgumentException if {@code extensionId} is not in the range 1-14.
45      * @throws NullPointerException if {@code extensionData} is null.
46      */
RtpHeaderExtension(@ntRangefrom = 1, to = 14) int localIdentifier, @NonNull byte[] extensionData)47     public RtpHeaderExtension(@IntRange(from = 1, to = 14) int localIdentifier,
48             @NonNull byte[] extensionData) {
49         if (localIdentifier < 1 || localIdentifier > 13) {
50             throw new IllegalArgumentException("localIdentifier must be in range 1-14");
51         }
52         if (extensionData == null) {
53             throw new NullPointerException("extensionDa is required.");
54         }
55         mLocalIdentifier = localIdentifier;
56         mExtensionData = extensionData;
57     }
58 
59     /**
60      * Creates a new instance of {@link RtpHeaderExtension} from a parcel.
61      * @param in The parceled data to read.
62      */
RtpHeaderExtension(@onNull Parcel in)63     private RtpHeaderExtension(@NonNull Parcel in) {
64         mLocalIdentifier = in.readInt();
65         mExtensionData = in.createByteArray();
66     }
67 
68     /**
69      * The local identifier for the RTP header extension.
70      * <p>
71      * Per RFC8285, the extension ID is a value in the range 1-14 (0 is reserved for padding and
72      * 15 is reserved for the one-byte header form.
73      * <p>
74      * Within the current call, this extension ID will match one of the
75      * {@link RtpHeaderExtensionType#getLocalIdentifier()}s.
76      *
77      * @return The local identifier for this RTP header extension.
78      */
79     @IntRange(from = 1, to = 14)
getLocalIdentifier()80     public int getLocalIdentifier() {
81         return mLocalIdentifier;
82     }
83 
84     /**
85      * The data payload for the RTP header extension.
86      * <p>
87      * Per RFC8285 Sec 4.3, an RTP header extension includes an 8-bit length field which indicate
88      * how many bytes of data are present in the RTP header extension.  The extension includes this
89      * many bytes of actual data.
90      * <p>
91      * We represent this as a byte array who's length is equivalent to the 8-bit length field.
92      * @return RTP header extension data payload.  The payload may be up to 255 bytes in length.
93      */
getExtensionData()94     public @NonNull byte[] getExtensionData() {
95         return mExtensionData;
96     }
97 
98     @Override
describeContents()99     public int describeContents() {
100         return 0;
101     }
102 
103     @Override
writeToParcel(@onNull Parcel dest, int flags)104     public void writeToParcel(@NonNull Parcel dest, int flags) {
105         dest.writeInt(mLocalIdentifier);
106         dest.writeByteArray(mExtensionData);
107     }
108 
109     public static final @NonNull Creator<RtpHeaderExtension> CREATOR =
110             new Creator<RtpHeaderExtension>() {
111                 @Override
112                 public RtpHeaderExtension createFromParcel(@NonNull Parcel in) {
113                     return new RtpHeaderExtension(in);
114                 }
115 
116                 @Override
117                 public RtpHeaderExtension[] newArray(int size) {
118                     return new RtpHeaderExtension[size];
119                 }
120             };
121 
122     @Override
equals(Object o)123     public boolean equals(Object o) {
124         if (this == o) return true;
125         if (o == null || getClass() != o.getClass()) return false;
126         RtpHeaderExtension that = (RtpHeaderExtension) o;
127         return mLocalIdentifier == that.mLocalIdentifier
128                 && Arrays.equals(mExtensionData, that.mExtensionData);
129     }
130 
131     @Override
hashCode()132     public int hashCode() {
133         int result = Objects.hash(mLocalIdentifier);
134         result = 31 * result + Arrays.hashCode(mExtensionData);
135         return result;
136     }
137 
138     @Override
toString()139     public String toString() {
140         StringBuilder sb = new StringBuilder();
141         sb.append("RtpHeaderExtension{mLocalIdentifier=");
142         sb.append(mLocalIdentifier);
143         sb.append(", mData=");
144         for (byte b : mExtensionData) {
145             sb.append(Integer.toBinaryString(b));
146             sb.append("b_");
147         }
148         sb.append("}");
149 
150         return sb.toString();
151     }
152 }
153