334 lines
11 KiB
Java
334 lines
11 KiB
Java
/*
|
|
* 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);
|
|
}
|
|
}
|
|
}
|