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