1 /* 2 * Copyright (C) 2022 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.NonNull; 20 import android.annotation.SystemApi; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 import android.telephony.ims.feature.MmTelFeature; 24 25 import java.util.Arrays; 26 import java.util.Objects; 27 import java.util.TreeSet; 28 29 /** 30 * A MediaThreshold represents a series of packet loss rate, jitter and rtp inactivity time 31 * thresholds which when crossed should result in a {@link MediaQualityStatus} report being 32 * generated by the {@link ImsService} via {@link MmTelFeature#notifyMediaQualityStatusChanged( 33 * MediaQualityStatus)} 34 * 35 * <p/> 36 * A {@link MediaQualityStatus} should be triggered when any of various 37 * attributes pass one of the thresholds defined here. 38 * 39 * @hide 40 */ 41 @SystemApi 42 public final class MediaThreshold implements Parcelable { 43 private final int[] mRtpPacketLossRate; 44 private final int[] mRtpJitter; 45 private final long[] mRtpInactivityTimeMillis; 46 47 /** 48 * Retrieves threshold values for RTP packet loss rate in percentage. 49 * 50 * @return int array including threshold values for packet loss rate 51 * 52 * @hide 53 */ 54 @NonNull 55 @SystemApi getThresholdsRtpPacketLossRate()56 public int[] getThresholdsRtpPacketLossRate() { 57 return mRtpPacketLossRate; 58 } 59 60 /** 61 * Retrieves threshold values for jitter(RFC3550) in milliseconds. 62 * 63 * @return int array including threshold values for RTP jitter. 64 */ 65 @NonNull getThresholdsRtpJitterMillis()66 public int[] getThresholdsRtpJitterMillis() { 67 return mRtpJitter; 68 } 69 70 /** 71 * Retrieves threshold values for RTP inactivity time in milliseconds. 72 * 73 * @return int array including threshold values for RTP inactivity time. 74 */ 75 @NonNull getThresholdsRtpInactivityTimeMillis()76 public long[] getThresholdsRtpInactivityTimeMillis() { 77 return mRtpInactivityTimeMillis; 78 } 79 MediaThreshold( int[] packetLossRateThresholds, int[] jitterThresholds, long[] inactivityTimeThresholds)80 private MediaThreshold( 81 int[] packetLossRateThresholds, 82 int[] jitterThresholds, 83 long[] inactivityTimeThresholds) { 84 mRtpPacketLossRate = packetLossRateThresholds; 85 mRtpJitter = jitterThresholds; 86 mRtpInactivityTimeMillis = inactivityTimeThresholds; 87 } 88 89 /** 90 * Creates a new instance of {@link MediaThreshold} from a parcel. 91 * @param in The parceled data to read. 92 */ MediaThreshold(@onNull Parcel in)93 private MediaThreshold(@NonNull Parcel in) { 94 mRtpPacketLossRate = in.createIntArray(); 95 mRtpJitter = in.createIntArray(); 96 mRtpInactivityTimeMillis = in.createLongArray(); 97 } 98 99 @Override writeToParcel(@onNull Parcel dest, int flags)100 public void writeToParcel(@NonNull Parcel dest, int flags) { 101 dest.writeIntArray(mRtpPacketLossRate); 102 dest.writeIntArray(mRtpJitter); 103 dest.writeLongArray(mRtpInactivityTimeMillis); 104 } 105 106 public static final @NonNull Creator<MediaThreshold> CREATOR = 107 new Creator<MediaThreshold>() { 108 @Override 109 public MediaThreshold createFromParcel(@NonNull Parcel in) { 110 return new MediaThreshold(in); 111 } 112 113 @Override 114 public MediaThreshold[] newArray(int size) { 115 return new MediaThreshold[size]; 116 } 117 }; 118 119 /** 120 * Returns whether the RTP packet loss rate threshold is valid or not. 121 * 122 * @param packetLossRate packet loss rate 123 * @return the threshold is valid or not. 124 * @hide 125 */ isValidRtpPacketLossRate(int packetLossRate)126 public static boolean isValidRtpPacketLossRate(int packetLossRate) { 127 return (packetLossRate >= 0 && packetLossRate <= 100); 128 } 129 130 /** 131 * Returns whether the RTP jitter threshold is valid or not. 132 * 133 * @param jitter jitter value in milliseconds 134 * @return the threshold is valid or not. 135 * @hide 136 */ isValidJitterMillis(int jitter)137 public static boolean isValidJitterMillis(int jitter) { 138 return (jitter >= 0 && jitter <= 10000); 139 } 140 141 /** 142 * Returns whether the RTP packet loss rate threshold is valid or not. 143 * 144 * @param inactivityTime packet loss rate 145 * @return the threshold is valid or not. 146 * @hide 147 */ isValidRtpInactivityTimeMillis(long inactivityTime)148 public static boolean isValidRtpInactivityTimeMillis(long inactivityTime) { 149 return (inactivityTime >= 0 && inactivityTime <= 60000); 150 } 151 152 @Override describeContents()153 public int describeContents() { 154 return 0; 155 } 156 157 @Override equals(Object o)158 public boolean equals(Object o) { 159 if (this == o) return true; 160 if (o == null || getClass() != o.getClass()) return false; 161 MediaThreshold that = (MediaThreshold) o; 162 return Arrays.equals(mRtpPacketLossRate, that.mRtpPacketLossRate) 163 && Arrays.equals(mRtpJitter, that.mRtpJitter) 164 && Arrays.equals(mRtpInactivityTimeMillis, that.mRtpInactivityTimeMillis); 165 } 166 167 @Override hashCode()168 public int hashCode() { 169 return Objects.hash(Arrays.hashCode(mRtpPacketLossRate), Arrays.hashCode(mRtpJitter), 170 Arrays.hashCode(mRtpInactivityTimeMillis)); 171 } 172 173 @Override toString()174 public String toString() { 175 StringBuilder sb = new StringBuilder(); 176 sb.append("MediaThreshold{mRtpPacketLossRate="); 177 for (int i : mRtpPacketLossRate) { 178 sb.append(" ").append(i); 179 } 180 sb.append(", mRtpJitter="); 181 for (int b : mRtpJitter) { 182 sb.append(" ").append(b); 183 } 184 sb.append(", mRtpInactivityTimeMillis="); 185 for (long i : mRtpInactivityTimeMillis) { 186 sb.append(" ").append(i); 187 } 188 sb.append("}"); 189 return sb.toString(); 190 } 191 192 /** 193 * Provides a convenient way to set the fields of an {@link MediaThreshold} when creating a 194 * new instance. 195 * 196 * <p>The example below shows how you might create a new {@code RtpThreshold}: 197 * 198 * <pre><code> 199 * 200 * RtpThreshold = new RtpThreshold.Builder() 201 * .setRtpSessionType({@link MediaQualityStatus#MEDIA_SESSION_TYPE_AUDIO} or 202 * {@link MediaQualityStatus#MEDIA_SESSION_TYPE_VIDEO}) 203 * .setThresholdsRtpPacketLossRate(int[] packetLossRateThresholds) 204 * .setThresholdsRtpJitterMillis(int[] jitterThresholds) 205 * .setThresholdsRtpInactivityTimeMillis(int[] inactivityTimeThresholds) 206 * .build(); 207 * </code></pre> 208 * 209 * @hide 210 */ 211 public static final class Builder { 212 private int[] mRtpPacketLossRate = null; 213 private int[] mRtpJitter = null; 214 private long[] mRtpInactivityTimeMillis = null; 215 216 /** 217 * Default constructor for the Builder. 218 * 219 * @hide 220 */ Builder()221 public Builder() { 222 } 223 224 /** 225 * Set threshold values for RTP packet loss rate in percentage. 226 * <p/> 227 * The packet loss calculation should be done at least once per 228 * second. It should be calculated with at least the last 3 seconds 229 * of data. 230 * 231 * @param packetLossRateThresholds int array for threshold values. 232 * @return The same instance of the builder. 233 * 234 * @hide 235 */ 236 @NonNull setThresholdsRtpPacketLossRate(int[] packetLossRateThresholds)237 public Builder setThresholdsRtpPacketLossRate(int[] packetLossRateThresholds) { 238 if (packetLossRateThresholds.length > 0) { 239 TreeSet<Integer> thresholds = new TreeSet<>(); 240 for (Integer value : packetLossRateThresholds) { 241 if (isValidRtpPacketLossRate(value)) { 242 thresholds.add(value); 243 } 244 } 245 int[] targetArray = new int[thresholds.size()]; 246 int i = 0; 247 for (int element : thresholds) { 248 targetArray[i++] = element; 249 } 250 this.mRtpPacketLossRate = targetArray; 251 } else { 252 this.mRtpPacketLossRate = packetLossRateThresholds; 253 } 254 return this; 255 } 256 257 258 /** 259 * Set threshold values for RTP jitter in Milliseconds. 260 * 261 * @param jitterThresholds int array including threshold values for Jitter. 262 * @return The same instance of the builder. 263 * 264 * @hide 265 */ 266 @NonNull setThresholdsRtpJitterMillis(int[] jitterThresholds)267 public Builder setThresholdsRtpJitterMillis(int[] jitterThresholds) { 268 if (jitterThresholds.length > 0) { 269 TreeSet<Integer> thresholds = new TreeSet<>(); 270 for (Integer value : jitterThresholds) { 271 if (isValidJitterMillis(value)) { 272 thresholds.add(value); 273 } 274 } 275 int[] targetArray = new int[thresholds.size()]; 276 int i = 0; 277 for (int element : thresholds) { 278 targetArray[i++] = element; 279 } 280 this.mRtpJitter = targetArray; 281 } else { 282 this.mRtpJitter = jitterThresholds; 283 } 284 return this; 285 } 286 287 /** 288 * Set threshold values for RTP inactivity time. 289 * 290 * @param inactivityTimeThresholds int array including threshold 291 * values for RTP inactivity time. 292 * @return The same instance of the builder. 293 * 294 * @hide 295 */ 296 @NonNull setThresholdsRtpInactivityTimeMillis(long[] inactivityTimeThresholds)297 public Builder setThresholdsRtpInactivityTimeMillis(long[] inactivityTimeThresholds) { 298 if (inactivityTimeThresholds.length > 0) { 299 TreeSet<Long> thresholds = new TreeSet<>(); 300 for (Long value : inactivityTimeThresholds) { 301 if (isValidRtpInactivityTimeMillis(value)) { 302 thresholds.add(value); 303 } 304 } 305 long[] targetArray = new long[thresholds.size()]; 306 int i = 0; 307 for (long element : thresholds) { 308 targetArray[i++] = element; 309 } 310 this.mRtpInactivityTimeMillis = targetArray; 311 } else { 312 this.mRtpInactivityTimeMillis = inactivityTimeThresholds; 313 } 314 return this; 315 } 316 317 /** 318 * Build the {@link MediaThreshold} 319 * 320 * @return the {@link MediaThreshold} object 321 * 322 * @hide 323 */ 324 @NonNull build()325 public MediaThreshold build() { 326 mRtpPacketLossRate = mRtpPacketLossRate != null ? mRtpPacketLossRate : new int[0]; 327 mRtpJitter = mRtpJitter != null ? mRtpJitter : new int[0]; 328 mRtpInactivityTimeMillis = 329 mRtpInactivityTimeMillis != null ? mRtpInactivityTimeMillis : new long[0]; 330 return new MediaThreshold(mRtpPacketLossRate, mRtpJitter, mRtpInactivityTimeMillis); 331 } 332 } 333 } 334