blob: 343aa4aab023cb493c84f9215a9271a8ab3b48a4 [file] [log] [blame]
/*
* Copyright (C) 2022 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.telephony.ims;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.ims.feature.MmTelFeature;
import java.util.Arrays;
import java.util.Objects;
import java.util.TreeSet;
/**
* A MediaThreshold represents a series of packet loss rate, jitter and rtp inactivity time
* thresholds which when crossed should result in a {@link MediaQualityStatus} report being
* generated by the {@link ImsService} via {@link MmTelFeature#notifyMediaQualityStatusChanged(
* MediaQualityStatus)}
*
* <p/>
* A {@link MediaQualityStatus} should be triggered when any of various
* attributes pass one of the thresholds defined here.
*
* @hide
*/
@SystemApi
public final class MediaThreshold implements Parcelable {
private final int[] mRtpPacketLossRate;
private final int[] mRtpJitter;
private final long[] mRtpInactivityTimeMillis;
/**
* Retrieves threshold values for RTP packet loss rate in percentage.
*
* @return int array including threshold values for packet loss rate
*
* @hide
*/
@NonNull
@SystemApi
public int[] getThresholdsRtpPacketLossRate() {
return mRtpPacketLossRate;
}
/**
* Retrieves threshold values for jitter(RFC3550) in milliseconds.
*
* @return int array including threshold values for RTP jitter.
*/
@NonNull
public int[] getThresholdsRtpJitterMillis() {
return mRtpJitter;
}
/**
* Retrieves threshold values for RTP inactivity time in milliseconds.
*
* @return int array including threshold values for RTP inactivity time.
*/
@NonNull
public long[] getThresholdsRtpInactivityTimeMillis() {
return mRtpInactivityTimeMillis;
}
private MediaThreshold(
int[] packetLossRateThresholds,
int[] jitterThresholds,
long[] inactivityTimeThresholds) {
mRtpPacketLossRate = packetLossRateThresholds;
mRtpJitter = jitterThresholds;
mRtpInactivityTimeMillis = inactivityTimeThresholds;
}
/**
* Creates a new instance of {@link MediaThreshold} from a parcel.
* @param in The parceled data to read.
*/
private MediaThreshold(@NonNull Parcel in) {
mRtpPacketLossRate = in.createIntArray();
mRtpJitter = in.createIntArray();
mRtpInactivityTimeMillis = in.createLongArray();
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeIntArray(mRtpPacketLossRate);
dest.writeIntArray(mRtpJitter);
dest.writeLongArray(mRtpInactivityTimeMillis);
}
public static final @NonNull Creator<MediaThreshold> CREATOR =
new Creator<MediaThreshold>() {
@Override
public MediaThreshold createFromParcel(@NonNull Parcel in) {
return new MediaThreshold(in);
}
@Override
public MediaThreshold[] newArray(int size) {
return new MediaThreshold[size];
}
};
/**
* Returns whether the RTP packet loss rate threshold is valid or not.
*
* @param packetLossRate packet loss rate
* @return the threshold is valid or not.
* @hide
*/
public static boolean isValidRtpPacketLossRate(int packetLossRate) {
return (packetLossRate >= 0 && packetLossRate <= 100);
}
/**
* Returns whether the RTP jitter threshold is valid or not.
*
* @param jitter jitter value in milliseconds
* @return the threshold is valid or not.
* @hide
*/
public static boolean isValidJitterMillis(int jitter) {
return (jitter >= 0 && jitter <= 10000);
}
/**
* Returns whether the RTP packet loss rate threshold is valid or not.
*
* @param inactivityTime packet loss rate
* @return the threshold is valid or not.
* @hide
*/
public static boolean isValidRtpInactivityTimeMillis(long inactivityTime) {
return (inactivityTime >= 0 && inactivityTime <= 60000);
}
@Override
public int describeContents() {
return 0;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MediaThreshold that = (MediaThreshold) o;
return Arrays.equals(mRtpPacketLossRate, that.mRtpPacketLossRate)
&& Arrays.equals(mRtpJitter, that.mRtpJitter)
&& Arrays.equals(mRtpInactivityTimeMillis, that.mRtpInactivityTimeMillis);
}
@Override
public int hashCode() {
return Objects.hash(Arrays.hashCode(mRtpPacketLossRate), Arrays.hashCode(mRtpJitter),
Arrays.hashCode(mRtpInactivityTimeMillis));
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("MediaThreshold{mRtpPacketLossRate=");
for (int i : mRtpPacketLossRate) {
sb.append(" ").append(i);
}
sb.append(", mRtpJitter=");
for (int b : mRtpJitter) {
sb.append(" ").append(b);
}
sb.append(", mRtpInactivityTimeMillis=");
for (long i : mRtpInactivityTimeMillis) {
sb.append(" ").append(i);
}
sb.append("}");
return sb.toString();
}
/**
* Provides a convenient way to set the fields of an {@link MediaThreshold} when creating a
* new instance.
*
* <p>The example below shows how you might create a new {@code RtpThreshold}:
*
* <pre><code>
*
* RtpThreshold = new RtpThreshold.Builder()
* .setRtpSessionType({@link MediaQualityStatus#MEDIA_SESSION_TYPE_AUDIO} or
* {@link MediaQualityStatus#MEDIA_SESSION_TYPE_VIDEO})
* .setThresholdsRtpPacketLossRate(int[] packetLossRateThresholds)
* .setThresholdsRtpJitterMillis(int[] jitterThresholds)
* .setThresholdsRtpInactivityTimeMillis(int[] inactivityTimeThresholds)
* .build();
* </code></pre>
*
* @hide
*/
public static final class Builder {
private int[] mRtpPacketLossRate = null;
private int[] mRtpJitter = null;
private long[] mRtpInactivityTimeMillis = null;
/**
* Default constructor for the Builder.
*
* @hide
*/
public Builder() {
}
/**
* Set threshold values for RTP packet loss rate in percentage.
* <p/>
* The packet loss calculation should be done at least once per
* second. It should be calculated with at least the last 3 seconds
* of data.
*
* @param packetLossRateThresholds int array for threshold values.
* @return The same instance of the builder.
*
* @hide
*/
@NonNull
public Builder setThresholdsRtpPacketLossRate(int[] packetLossRateThresholds) {
if (packetLossRateThresholds.length > 0) {
TreeSet<Integer> thresholds = new TreeSet<>();
for (Integer value : packetLossRateThresholds) {
if (isValidRtpPacketLossRate(value)) {
thresholds.add(value);
}
}
int[] targetArray = new int[thresholds.size()];
int i = 0;
for (int element : thresholds) {
targetArray[i++] = element;
}
this.mRtpPacketLossRate = targetArray;
} else {
this.mRtpPacketLossRate = packetLossRateThresholds;
}
return this;
}
/**
* Set threshold values for RTP jitter in Milliseconds.
*
* @param jitterThresholds int array including threshold values for Jitter.
* @return The same instance of the builder.
*
* @hide
*/
@NonNull
public Builder setThresholdsRtpJitterMillis(int[] jitterThresholds) {
if (jitterThresholds.length > 0) {
TreeSet<Integer> thresholds = new TreeSet<>();
for (Integer value : jitterThresholds) {
if (isValidJitterMillis(value)) {
thresholds.add(value);
}
}
int[] targetArray = new int[thresholds.size()];
int i = 0;
for (int element : thresholds) {
targetArray[i++] = element;
}
this.mRtpJitter = targetArray;
} else {
this.mRtpJitter = jitterThresholds;
}
return this;
}
/**
* Set threshold values for RTP inactivity time.
*
* @param inactivityTimeThresholds int array including threshold
* values for RTP inactivity time.
* @return The same instance of the builder.
*
* @hide
*/
@NonNull
public Builder setThresholdsRtpInactivityTimeMillis(long[] inactivityTimeThresholds) {
if (inactivityTimeThresholds.length > 0) {
TreeSet<Long> thresholds = new TreeSet<>();
for (Long value : inactivityTimeThresholds) {
if (isValidRtpInactivityTimeMillis(value)) {
thresholds.add(value);
}
}
long[] targetArray = new long[thresholds.size()];
int i = 0;
for (long element : thresholds) {
targetArray[i++] = element;
}
this.mRtpInactivityTimeMillis = targetArray;
} else {
this.mRtpInactivityTimeMillis = inactivityTimeThresholds;
}
return this;
}
/**
* Build the {@link MediaThreshold}
*
* @return the {@link MediaThreshold} object
*
* @hide
*/
@NonNull
public MediaThreshold build() {
mRtpPacketLossRate = mRtpPacketLossRate != null ? mRtpPacketLossRate : new int[0];
mRtpJitter = mRtpJitter != null ? mRtpJitter : new int[0];
mRtpInactivityTimeMillis =
mRtpInactivityTimeMillis != null ? mRtpInactivityTimeMillis : new long[0];
return new MediaThreshold(mRtpPacketLossRate, mRtpJitter, mRtpInactivityTimeMillis);
}
}
}