Merge "Media quality CB: API interface"

This commit is contained in:
Sewook Seo
2022-12-20 06:44:35 +00:00
committed by Android (Google) Code Review
15 changed files with 1053 additions and 3 deletions

View File

@@ -13795,6 +13795,7 @@ package android.telephony {
field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_IMS_CALL_DISCONNECT_CAUSE_CHANGED = 28; // 0x1c
field @RequiresPermission(android.Manifest.permission.READ_CALL_LOG) public static final int EVENT_LEGACY_CALL_STATE_CHANGED = 36; // 0x24
field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_LINK_CAPACITY_ESTIMATE_CHANGED = 37; // 0x25
field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_MEDIA_QUALITY_STATUS_CHANGED = 39; // 0x27
field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_MESSAGE_WAITING_INDICATOR_CHANGED = 3; // 0x3
field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_OEM_HOOK_RAW = 15; // 0xf
field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int EVENT_OUTGOING_EMERGENCY_CALL = 29; // 0x1d
@@ -13830,6 +13831,10 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onLinkCapacityEstimateChanged(@NonNull java.util.List<android.telephony.LinkCapacityEstimate>);
}
public static interface TelephonyCallback.MediaQualityStatusChangedListener {
method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onMediaQualityStatusChanged(@NonNull android.telephony.ims.MediaQualityStatus);
}
public static interface TelephonyCallback.OutgoingEmergencyCallListener {
method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber, int);
}
@@ -15372,6 +15377,37 @@ package android.telephony.ims {
method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile);
}
public final class MediaQualityStatus implements android.os.Parcelable {
method public int describeContents();
method @NonNull public String getCallSessionId();
method public int getMediaSessionType();
method public long getRtpInactivityMillis();
method public int getRtpJitterMillis();
method @IntRange(from=0, to=100) public int getRtpPacketLossRate();
method public int getTransportType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.MediaQualityStatus> CREATOR;
field public static final int MEDIA_SESSION_TYPE_AUDIO = 1; // 0x1
field public static final int MEDIA_SESSION_TYPE_VIDEO = 2; // 0x2
}
public static final class MediaQualityStatus.Builder {
ctor public MediaQualityStatus.Builder(@NonNull String, int, int);
method @NonNull public android.telephony.ims.MediaQualityStatus build();
method @NonNull public android.telephony.ims.MediaQualityStatus.Builder setRtpInactivityMillis(long);
method @NonNull public android.telephony.ims.MediaQualityStatus.Builder setRtpJitterMillis(int);
method @NonNull public android.telephony.ims.MediaQualityStatus.Builder setRtpPacketLossRate(@IntRange(from=0, to=100) int);
}
public final class MediaThreshold implements android.os.Parcelable {
method public int describeContents();
method @NonNull public long[] getThresholdsRtpInactivityTimeMillis();
method @NonNull public int[] getThresholdsRtpJitterMillis();
method @NonNull public int[] getThresholdsRtpPacketLossRate();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.MediaThreshold> CREATOR;
}
public class ProvisioningManager {
method @NonNull public static android.telephony.ims.ProvisioningManager createForSubscriptionId(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public int getProvisioningIntValue(int);
@@ -15823,6 +15859,7 @@ package android.telephony.ims.feature {
ctor public MmTelFeature(@NonNull java.util.concurrent.Executor);
method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
method public void changeOfferedRtpHeaderExtensionTypes(@NonNull java.util.Set<android.telephony.ims.RtpHeaderExtensionType>);
method public void clearMediaThreshold(int);
method @Nullable public android.telephony.ims.ImsCallProfile createCallProfile(int, int);
method @Nullable public android.telephony.ims.stub.ImsCallSessionImplBase createCallSession(@NonNull android.telephony.ims.ImsCallProfile);
method @NonNull public android.telephony.ims.stub.ImsEcbmImplBase getEcbm();
@@ -15832,6 +15869,7 @@ package android.telephony.ims.feature {
method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.MmTelFeature.MmTelCapabilities);
method @Deprecated public final void notifyIncomingCall(@NonNull android.telephony.ims.stub.ImsCallSessionImplBase, @NonNull android.os.Bundle);
method @Nullable public final android.telephony.ims.ImsCallSessionListener notifyIncomingCall(@NonNull android.telephony.ims.stub.ImsCallSessionImplBase, @NonNull String, @NonNull android.os.Bundle);
method public final void notifyMediaQualityStatusChanged(@NonNull android.telephony.ims.MediaQualityStatus);
method public final void notifyRejectedCall(@NonNull android.telephony.ims.ImsCallProfile, @NonNull android.telephony.ims.ImsReasonInfo);
method public void notifySrvccCanceled();
method public void notifySrvccCompleted();
@@ -15842,7 +15880,9 @@ package android.telephony.ims.feature {
method public void onFeatureRemoved();
method public boolean queryCapabilityConfiguration(int, int);
method @NonNull public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus();
method @Nullable public android.telephony.ims.MediaQualityStatus queryMediaQualityStatus(int);
method public final void setCallAudioHandler(int);
method public void setMediaThreshold(int, @NonNull android.telephony.ims.MediaThreshold);
method public void setTerminalBasedCallWaitingStatus(boolean);
method public void setUiTtyMode(int, @Nullable android.os.Message);
method public int shouldProcessCall(@NonNull String[]);

View File

@@ -34,6 +34,7 @@ import android.telephony.Annotation.SrvccState;
import android.telephony.TelephonyManager.DataEnabledReason;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.MediaQualityStatus;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.IPhoneStateListener;
@@ -1664,6 +1665,10 @@ public class PhoneStateListener {
List<LinkCapacityEstimate> linkCapacityEstimateList) {
// default implementation empty
}
public final void onMediaQualityStatusChanged(MediaQualityStatus mediaQualityStatus) {
// not support. Can't override. Use TelephonyCallback.
}
}
private void log(String s) {

View File

@@ -27,6 +27,8 @@ import android.os.Binder;
import android.os.Build;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.MediaQualityStatus;
import android.telephony.ims.MediaThreshold;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -591,6 +593,19 @@ public class TelephonyCallback {
*/
public static final int EVENT_TRIGGER_NOTIFY_ANBR = 38;
/**
* Event for changes to the media quality status
*
* <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
*
* @see MediaQualityStatusChangedListener#onMediaQualityStatusChanged
*
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public static final int EVENT_MEDIA_QUALITY_STATUS_CHANGED = 39;
/**
* @hide
*/
@@ -632,7 +647,8 @@ public class TelephonyCallback {
EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED,
EVENT_LEGACY_CALL_STATE_CHANGED,
EVENT_LINK_CAPACITY_ESTIMATE_CHANGED,
EVENT_TRIGGER_NOTIFY_ANBR
EVENT_TRIGGER_NOTIFY_ANBR,
EVENT_MEDIA_QUALITY_STATUS_CHANGED
})
@Retention(RetentionPolicy.SOURCE)
public @interface TelephonyEvent {
@@ -1516,6 +1532,30 @@ public class TelephonyCallback {
@NonNull List<LinkCapacityEstimate> linkCapacityEstimateList);
}
/**
* Interface for media quality status changed listener.
*
* @hide
*/
@SystemApi
public interface MediaQualityStatusChangedListener {
/**
* Callback invoked when the media quality status of IMS call changes. This call back
* means current media quality status crosses at least one of threshold values in {@link
* MediaThreshold}. Listener needs to get quality information & check whether it crossed
* listener's threshold.
*
* <p/> Currently thresholds for this indication can be configurable by CARRIER_CONFIG
* {@link CarrierConfigManager#KEY_VOICE_RTP_THRESHOLDS_PACKET_LOSS_RATE_INT}
* {@link CarrierConfigManager#KEY_VOICE_RTP_THRESHOLDS_INACTIVITY_TIME_IN_MILLIS_INT}
* {@link CarrierConfigManager#KEY_VOICE_RTP_THRESHOLDS_JITTER_INT}
*
* @param mediaQualityStatus The media quality status currently measured.
*/
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
void onMediaQualityStatusChanged(@NonNull MediaQualityStatus mediaQualityStatus);
}
/**
* The callback methods need to be called on the handler thread where
* this object was created. If the binder did that for us it'd be nice.
@@ -1873,5 +1913,16 @@ public class TelephonyCallback {
() -> mExecutor.execute(() -> listener.onLinkCapacityEstimateChanged(
linkCapacityEstimateList)));
}
public void onMediaQualityStatusChanged(
MediaQualityStatus mediaQualityStatus) {
MediaQualityStatusChangedListener listener =
(MediaQualityStatusChangedListener) mTelephonyCallbackWeakRef.get();
if (listener == null) return;
Binder.withCleanCallingIdentity(
() -> mExecutor.execute(() -> listener.onMediaQualityStatusChanged(
mediaQualityStatus)));
}
}
}

View File

@@ -40,6 +40,7 @@ import android.telephony.TelephonyManager.CarrierPrivilegesCallback;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsCallSession;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.MediaQualityStatus;
import android.util.ArraySet;
import android.util.Log;
@@ -544,6 +545,27 @@ public class TelephonyRegistryManager {
}
}
/**
* Notify change of media quality status {@link MediaQualityStatus} crosses media quality
* threshold
* <p/>
* Currently thresholds for this indication can be configurable by CARRIER_CONFIG
* {@link CarrierConfigManager#KEY_VOICE_RTP_THRESHOLDS_PACKET_LOSS_RATE_INT}
* {@link CarrierConfigManager#KEY_VOICE_RTP_THRESHOLDS_INACTIVITY_TIME_IN_MILLIS_INT}
* {@link CarrierConfigManager#KEY_VOICE_RTP_THRESHOLDS_JITTER_INT}
*
* @param status media quality status
*/
public void notifyMediaQualityStatusChanged(
int slotIndex, int subId, @NonNull MediaQualityStatus status) {
try {
sRegistry.notifyMediaQualityStatusChanged(slotIndex, subId, status);
} catch (RemoteException ex) {
// system server crash
throw ex.rethrowFromSystemServer();
}
}
/**
* Notify emergency number list changed on certain subscription.
*
@@ -1087,6 +1109,10 @@ public class TelephonyRegistryManager {
eventList.add(TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED);
}
if (telephonyCallback instanceof TelephonyCallback.MediaQualityStatusChangedListener) {
eventList.add(TelephonyCallback.EVENT_MEDIA_QUALITY_STATUS_CHANGED);
}
return eventList;
}

View File

@@ -31,6 +31,7 @@ import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.MediaQualityStatus;
/**
* {@hide}
@@ -76,4 +77,5 @@ oneway interface IPhoneStateListener {
void onDataEnabledChanged(boolean enabled, int reason);
void onAllowedNetworkTypesChanged(in int reason, in long allowedNetworkType);
void onLinkCapacityEstimateChanged(in List<LinkCapacityEstimate> linkCapacityEstimateList);
void onMediaQualityStatusChanged(in MediaQualityStatus mediaQualityStatus);
}

View File

@@ -32,6 +32,8 @@ import android.telephony.PreciseDataConnectionState;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.MediaQualityStatus;
import com.android.internal.telephony.ICarrierConfigChangeListener;
import com.android.internal.telephony.ICarrierPrivilegesCallback;
import com.android.internal.telephony.IPhoneStateListener;
@@ -92,6 +94,7 @@ interface ITelephonyRegistry {
in EmergencyNumber emergencyNumber);
void notifyCallQualityChanged(in CallQuality callQuality, int phoneId, int subId,
int callNetworkType);
void notifyMediaQualityStatusChanged(int phoneId, int subId, in MediaQualityStatus status);
void notifyImsDisconnectCause(int subId, in ImsReasonInfo imsReasonInfo);
void notifyRegistrationFailed(int slotIndex, int subId, in CellIdentity cellIdentity,
String chosenPlmn, int domain, int causeCode, int additionalCauseCode);

View File

@@ -84,11 +84,13 @@ import android.telephony.data.ApnSetting;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsCallSession;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.MediaQualityStatus;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LocalLog;
import android.util.Pair;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
@@ -357,6 +359,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private CallQuality[] mCallQuality;
private List<SparseArray<MediaQualityStatus>> mMediaQualityStatus;
private ArrayList<List<CallState>> mCallStateLists;
// network type of the call associated with the mCallStateLists and mCallQuality
@@ -483,6 +487,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
TelephonyCallback.EVENT_DATA_ENABLED_CHANGED);
REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED);
REQUIRE_PRECISE_PHONE_STATE_PERMISSION.add(
TelephonyCallback.EVENT_MEDIA_QUALITY_STATUS_CHANGED);
}
private boolean isLocationPermissionRequired(Set<Integer> events) {
@@ -715,6 +721,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
cutListToSize(mCarrierPrivilegeStates, mNumPhones);
cutListToSize(mCarrierServiceStates, mNumPhones);
cutListToSize(mCallStateLists, mNumPhones);
cutListToSize(mMediaQualityStatus, mNumPhones);
return;
}
@@ -738,6 +745,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
mCallQuality[i] = createCallQuality();
mMediaQualityStatus.add(i, new SparseArray<>());
mCallStateLists.add(i, new ArrayList<>());
mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
mPreciseCallState[i] = createPreciseCallState();
@@ -805,6 +813,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mCallDisconnectCause = new int[numPhones];
mCallPreciseDisconnectCause = new int[numPhones];
mCallQuality = new CallQuality[numPhones];
mMediaQualityStatus = new ArrayList<>();
mCallNetworkType = new int[numPhones];
mCallStateLists = new ArrayList<>();
mPreciseDataConnectionStates = new ArrayList<>();
@@ -844,6 +853,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
mCallQuality[i] = createCallQuality();
mMediaQualityStatus.add(i, new SparseArray<>());
mCallStateLists.add(i, new ArrayList<>());
mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
mPreciseCallState[i] = createPreciseCallState();
@@ -1392,6 +1402,32 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
remove(r.binder);
}
}
if (events.contains(TelephonyCallback.EVENT_MEDIA_QUALITY_STATUS_CHANGED)) {
CallState callState = null;
for (CallState cs : mCallStateLists.get(r.phoneId)) {
if (cs.getCallState() == PreciseCallState.PRECISE_CALL_STATE_ACTIVE) {
callState = cs;
break;
}
}
if (callState != null) {
String callId = callState.getImsCallSessionId();
try {
MediaQualityStatus status = mMediaQualityStatus.get(r.phoneId).get(
MediaQualityStatus.MEDIA_SESSION_TYPE_AUDIO);
if (status != null && status.getCallSessionId().equals(callId)) {
r.callback.onMediaQualityStatusChanged(status);
}
status = mMediaQualityStatus.get(r.phoneId).get(
MediaQualityStatus.MEDIA_SESSION_TYPE_VIDEO);
if (status != null && status.getCallSessionId().equals(callId)) {
r.callback.onMediaQualityStatusChanged(status);
}
} catch (RemoteException ex) {
remove(r.binder);
}
}
}
}
}
}
@@ -2283,6 +2319,17 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
mCallStateLists.get(phoneId).add(builder.build());
}
boolean hasOngoingCall = false;
for (CallState cs : mCallStateLists.get(phoneId)) {
if (cs.getCallState() != PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED) {
hasOngoingCall = true;
break;
}
}
if (!hasOngoingCall) {
//no ongoing call. clear media quality status cached.
mMediaQualityStatus.get(phoneId).clear();
}
}
for (Record r : mRecords) {
@@ -2626,7 +2673,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
}
handleRemoveListLocked();
}
}
@@ -3127,6 +3173,55 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
@Override
public void notifyMediaQualityStatusChanged(int phoneId, int subId, MediaQualityStatus status) {
if (!checkNotifyPermission("notifyMediaQualityStatusChanged()")) {
return;
}
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
if (mCallStateLists.get(phoneId).size() > 0) {
CallState callState = null;
for (CallState cs : mCallStateLists.get(phoneId)) {
if (cs.getCallState() == PreciseCallState.PRECISE_CALL_STATE_ACTIVE) {
callState = cs;
break;
}
}
if (callState != null) {
String callSessionId = callState.getImsCallSessionId();
if (callSessionId != null
&& callSessionId.equals(status.getCallSessionId())) {
mMediaQualityStatus.get(phoneId)
.put(status.getMediaSessionType(), status);
} else {
log("SessionId mismatch active call:" + callSessionId
+ " media quality:" + status.getCallSessionId());
return;
}
} else {
log("There is no active call to report CallQaulity");
return;
}
}
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_MEDIA_QUALITY_STATUS_CHANGED)
&& idMatch(r, subId, phoneId)) {
try {
r.callback.onMediaQualityStatusChanged(status);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
}
}
}
handleRemoveListLocked();
}
}
@NeverCompile // Avoid size overhead of debugging code.
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {

View File

@@ -45,6 +45,7 @@ import android.telephony.gba.UaSecurityProtocolIdentifier;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ImsRegistrationAttributes;
import android.telephony.ims.ImsSsData;
import android.telephony.ims.MediaQualityStatus;
import android.telephony.ims.RcsUceAdapter;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.feature.RcsFeature;
@@ -6347,6 +6348,50 @@ public class CarrierConfigManager {
public static final String KEY_DTMFNB_PAYLOAD_TYPE_INT_ARRAY =
KEY_PREFIX + "dtmfnb_payload_type_int_array";
/**
* This indicates the threshold for RTP packet loss rate in percentage. If measured packet
* loss rate crosses this, a callback with {@link MediaQualityStatus} will be invoked to
* listeners.
* See {@link android.telephony.TelephonyCallback.MediaQualityStatusChangedListener}
*
* <p/>
* Valid threshold range : 0 ~ 100
*
* @hide
*/
public static final String KEY_VOICE_RTP_PACKET_LOSS_RATE_THRESHOLD_INT =
KEY_PREFIX + "rtp_packet_loss_rate_threshold_int";
/**
* This indicates the threshold for RTP jitter value in milliseconds (RFC3550). If measured
* jitter value crosses this, a callback with {@link MediaQualityStatus} will be invoked
* to listeners.
* See {@link android.telephony.TelephonyCallback.MediaQualityStatusChangedListener}
*
* <p/>
* Valid threshold range : 0 ~ 10000
*
* @hide
*/
public static final String KEY_VOICE_RTP_JITTER_THRESHOLD_MILLIS_INT =
KEY_PREFIX + "rtp_jitter_threshold_millis_int";
/**
* This indicates the threshold for RTP inactivity time in milliseconds. If measured
* inactivity timer crosses this, a callback with {@link MediaQualityStatus} will be invoked
* to listeners.
* See {@link android.telephony.TelephonyCallback.MediaQualityStatusChangedListener}
*
* <p/>
* Valid threshold range : 0 ~ 60000
*
* @hide
*/
public static final String KEY_VOICE_RTP_INACTIVITY_TIME_THRESHOLD_MILLIS_LONG =
KEY_PREFIX + "rtp_inactivity_time_threshold_millis_long";
/** @hide */
@IntDef({
BANDWIDTH_EFFICIENT,
@@ -6833,6 +6878,9 @@ public class CarrierConfigManager {
defaults.putInt(KEY_AUDIO_AS_BANDWIDTH_KBPS_INT, 41);
defaults.putInt(KEY_AUDIO_RS_BANDWIDTH_BPS_INT, 600);
defaults.putInt(KEY_AUDIO_RR_BANDWIDTH_BPS_INT, 2000);
defaults.putInt(KEY_VOICE_RTP_PACKET_LOSS_RATE_THRESHOLD_INT, 40);
defaults.putInt(KEY_VOICE_RTP_JITTER_THRESHOLD_MILLIS_INT, 120);
defaults.putLong(KEY_VOICE_RTP_INACTIVITY_TIME_THRESHOLD_MILLIS_LONG, 5000);
defaults.putIntArray(
KEY_AUDIO_INACTIVITY_CALL_END_REASONS_INT_ARRAY,

View File

@@ -0,0 +1,19 @@
/*
* 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;
parcelable MediaQualityStatus;

View File

@@ -0,0 +1,287 @@
/*
* 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.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.AccessNetworkConstants.TransportType;
import java.util.Objects;
/**
* A representation of Media quality status.
*
* @hide
*/
@SystemApi
public final class MediaQualityStatus implements Parcelable {
public static final int MEDIA_SESSION_TYPE_AUDIO = 1;
public static final int MEDIA_SESSION_TYPE_VIDEO = 2;
private final String mImsCallSessionId;
private final int mMediaSessionType;
private final int mTransportType;
private final int mRtpPacketLossRate;
private final int mRtpJitter;
private final long mRtpInactivityTimeMillis;
/** @hide */
@IntDef(
value = {
MEDIA_SESSION_TYPE_AUDIO,
MEDIA_SESSION_TYPE_VIDEO,
})
public @interface MediaSessionType {}
/**
* Constructor for this
*
* @param imsCallSessionId IMS call session id of this quality status
* @param mediaSessionType media session type of this quality status
* @param transportType transport type of this quality status
* @param rtpPacketLossRate measured RTP packet loss rate
* @param rtpJitter measured RTP jitter value
* @param rptInactivityTimeMillis measured RTP inactivity time in milliseconds
*/
private MediaQualityStatus(@NonNull String imsCallSessionId,
@MediaSessionType int mediaSessionType, @TransportType int transportType,
int rtpPacketLossRate, int rtpJitter, long rptInactivityTimeMillis) {
mImsCallSessionId = imsCallSessionId;
mMediaSessionType = mediaSessionType;
mTransportType = transportType;
mRtpPacketLossRate = rtpPacketLossRate;
mRtpJitter = rtpJitter;
mRtpInactivityTimeMillis = rptInactivityTimeMillis;
}
/**
* Retrieves call session ID for this quality status
*/
@NonNull
public String getCallSessionId() {
return mImsCallSessionId;
}
/**
* Retrieves media session type of this quality status
*/
public @MediaSessionType int getMediaSessionType() {
return mMediaSessionType;
}
/**
* Retrieves Transport type for which this media quality was measured.
*/
public @TransportType int getTransportType() {
return mTransportType;
}
/**
* Retrieves measured RTP packet loss rate in percentage.
*/
@IntRange(from = 0, to = 100)
public int getRtpPacketLossRate() {
return mRtpPacketLossRate;
}
/**
* Retrieves measured RTP jitter(RFC3550) value in milliseconds
*/
public int getRtpJitterMillis() {
return mRtpJitter;
}
/**
* Retrieves measured RTP inactivity time in milliseconds
*/
public long getRtpInactivityMillis() {
return mRtpInactivityTimeMillis;
}
/**
* Creates a new instance of {@link MediaQualityStatus} from a parcel.
* @param in The parceled data to read.
*/
private MediaQualityStatus(@NonNull Parcel in) {
mImsCallSessionId = in.readString();
mMediaSessionType = in.readInt();
mTransportType = in.readInt();
mRtpPacketLossRate = in.readInt();
mRtpJitter = in.readInt();
mRtpInactivityTimeMillis = in.readLong();
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mImsCallSessionId);
dest.writeInt(mMediaSessionType);
dest.writeInt(mTransportType);
dest.writeInt(mRtpPacketLossRate);
dest.writeInt(mRtpJitter);
dest.writeLong(mRtpInactivityTimeMillis);
}
public static final @NonNull Creator<MediaQualityStatus> CREATOR =
new Creator<MediaQualityStatus>() {
@Override
public MediaQualityStatus createFromParcel(@NonNull Parcel in) {
return new MediaQualityStatus(in);
}
@Override
public MediaQualityStatus[] newArray(int size) {
return new MediaQualityStatus[size];
}
};
@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;
MediaQualityStatus that = (MediaQualityStatus) o;
return mImsCallSessionId != null && mImsCallSessionId.equals(that.mImsCallSessionId)
&& mMediaSessionType == that.mMediaSessionType
&& mTransportType == that.mTransportType
&& mRtpPacketLossRate == that.mRtpPacketLossRate
&& mRtpJitter == that.mRtpJitter
&& mRtpInactivityTimeMillis == that.mRtpInactivityTimeMillis;
}
@Override
public int hashCode() {
return Objects.hash(mImsCallSessionId, mMediaSessionType, mTransportType,
mRtpPacketLossRate, mRtpJitter, mRtpInactivityTimeMillis);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("MediaThreshold{mImsCallSessionId=");
sb.append(mImsCallSessionId);
sb.append(", mMediaSessionType=");
sb.append(mMediaSessionType);
sb.append(", mTransportType=");
sb.append(mTransportType);
sb.append(", mRtpPacketLossRate=");
sb.append(mRtpPacketLossRate);
sb.append(", mRtpJitter=");
sb.append(mRtpJitter);
sb.append(", mRtpInactivityTimeMillis=");
sb.append(mRtpInactivityTimeMillis);
sb.append("}");
return sb.toString();
}
/**
* Provides a convenient way to set the fields of an {@link MediaQualityStatus} when creating a
* new instance.
*
* <p>The example below shows how you might create a new {@code RtpQualityStatus}:
*
* <pre><code>
*
* MediaQualityStatus = new MediaQualityStatus.Builder(
* callSessionId, mediaSessionType, transportType)
* .setRtpPacketLossRate(packetLossRate)
* .setRtpJitter(jitter)
* .setRtpInactivityMillis(inactivityTimeMillis)
* .build();
* </code></pre>
*/
public static final class Builder {
private final String mImsCallSessionId;
private final int mMediaSessionType;
private final int mTransportType;
private int mRtpPacketLossRate;
private int mRtpJitter;
private long mRtpInactivityTimeMillis;
/**
* Default constructor for the Builder.
*/
public Builder(
@NonNull String imsCallSessionId,
@MediaSessionType int mediaSessionType,
int transportType) {
mImsCallSessionId = imsCallSessionId;
mMediaSessionType = mediaSessionType;
mTransportType = transportType;
}
/**
* Set RTP packet loss info.
*
* @param packetLossRate RTP packet loss rate in percentage
* @return The same instance of the builder.
*/
@NonNull
public Builder setRtpPacketLossRate(@IntRange(from = 0, to = 100) int packetLossRate) {
this.mRtpPacketLossRate = packetLossRate;
return this;
}
/**
* Set calculated RTP jitter(RFC3550) value in milliseconds.
*
* @param jitter calculated RTP jitter value.
* @return The same instance of the builder.
*/
@NonNull
public Builder setRtpJitterMillis(int jitter) {
this.mRtpJitter = jitter;
return this;
}
/**
* Set measured RTP inactivity time.
*
* @param inactivityTimeMillis RTP inactivity time in Milliseconds.
* @return The same instance of the builder.
*/
@NonNull
public Builder setRtpInactivityMillis(long inactivityTimeMillis) {
this.mRtpInactivityTimeMillis = inactivityTimeMillis;
return this;
}
/**
* Build the {@link MediaQualityStatus}
*
* @return the {@link MediaQualityStatus} object
*/
@NonNull
public MediaQualityStatus build() {
return new MediaQualityStatus(
mImsCallSessionId,
mMediaSessionType,
mTransportType,
mRtpPacketLossRate,
mRtpJitter,
mRtpInactivityTimeMillis);
}
}
}

View File

@@ -0,0 +1,19 @@
/*
* 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;
parcelable MediaThreshold;

View File

@@ -0,0 +1,333 @@
/*
* 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);
}
}
}

View File

@@ -22,6 +22,8 @@ import android.telephony.ims.aidl.IImsSmsListener;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.ISrvccStartedCallback;
import android.telephony.ims.feature.CapabilityChangeRequest;
import android.telephony.ims.MediaQualityStatus;
import android.telephony.ims.MediaThreshold;
import android.telephony.ims.RtpHeaderExtensionType;
import android.telephony.ims.ImsCallProfile;
@@ -60,6 +62,9 @@ interface IImsMmTelFeature {
oneway void notifySrvccCompleted();
oneway void notifySrvccFailed();
oneway void notifySrvccCanceled();
oneway void setMediaQualityThreshold(int mediaSessionType, in MediaThreshold threshold);
MediaQualityStatus queryMediaQualityStatus(int mediaSessionType);
// SMS APIs
void setSmsListener(IImsSmsListener l);
oneway void sendSms(in int token, int messageRef, String format, String smsc, boolean retry,

View File

@@ -20,6 +20,7 @@ import android.os.Bundle;
import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.MediaQualityStatus;
import android.telephony.ims.aidl.IImsCallSessionListener;
import android.telephony.ims.aidl.IImsTrafficSessionCallback;
@@ -42,4 +43,5 @@ interface IImsMmTelListener {
int trafficDirection, in IImsTrafficSessionCallback callback);
oneway void onModifyImsTrafficSession(int token, int accessNetworkType);
oneway void onStopImsTrafficSession(int token);
oneway void onMediaQualityStatusChanged(in MediaQualityStatus status);
}

View File

@@ -34,6 +34,8 @@ import android.telephony.ims.ImsCallSessionListener;
import android.telephony.ims.ImsException;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ImsService;
import android.telephony.ims.MediaQualityStatus;
import android.telephony.ims.MediaThreshold;
import android.telephony.ims.RtpHeaderExtensionType;
import android.telephony.ims.SrvccCall;
import android.telephony.ims.aidl.IImsCallSessionListener;
@@ -257,7 +259,7 @@ public class MmTelFeature extends ImsFeature {
public void changeCapabilitiesConfiguration(CapabilityChangeRequest request,
IImsCapabilityCallback c) {
executeMethodAsyncNoException(() -> MmTelFeature.this
.requestChangeEnabledCapabilities(request, c),
.requestChangeEnabledCapabilities(request, c),
"changeCapabilitiesConfiguration");
}
@@ -268,6 +270,26 @@ public class MmTelFeature extends ImsFeature {
capability, radioTech, c), "queryCapabilityConfiguration");
}
@Override
public void setMediaQualityThreshold(@MediaQualityStatus.MediaSessionType int sessionType,
MediaThreshold mediaThreshold) {
if (mediaThreshold != null) {
executeMethodAsyncNoException(() -> setMediaThreshold(sessionType, mediaThreshold),
"setMediaQualityThreshold");
} else {
executeMethodAsyncNoException(() -> clearMediaThreshold(sessionType),
"clearMediaQualityThreshold");
}
}
@Override
public MediaQualityStatus queryMediaQualityStatus(
@MediaQualityStatus.MediaSessionType int sessionType)
throws RemoteException {
return executeMethodAsyncForResult(() -> MmTelFeature.this.queryMediaQualityStatus(
sessionType), "queryMediaQualityStatus");
}
@Override
public void setSmsListener(IImsSmsListener l) {
executeMethodAsyncNoException(() -> MmTelFeature.this.setSmsListener(l),
@@ -696,6 +718,17 @@ public class MmTelFeature extends ImsFeature {
public void onStopImsTrafficSession(int token) {
}
/**
* Called when the IMS provider notifies {@link MediaQualityStatus}.
*
* @param status media quality status currently measured.
* @hide
*/
@Override
public void onMediaQualityStatusChanged(MediaQualityStatus status) {
}
}
/**
@@ -1059,6 +1092,32 @@ public class MmTelFeature extends ImsFeature {
super.notifyCapabilitiesStatusChanged(c);
}
/**
* Notify the framework that the measured media quality has crossed a threshold set by {@link
* MmTelFeature#setMediaThreshold}
*
* @param status current media quality status measured.
* @hide
*/
@SystemApi
public final void notifyMediaQualityStatusChanged(
@NonNull MediaQualityStatus status) {
if (status == null) {
throw new IllegalArgumentException(
"MediaQualityStatus must be non-null!");
}
Log.i(LOG_TAG, "notifyMediaQualityStatusChanged " + status);
IImsMmTelListener listener = getListener();
if (listener == null) {
throw new IllegalStateException("Session is not available.");
}
try {
listener.onMediaQualityStatusChanged(status);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
/**
* Notify the framework of an incoming call.
* @param c The {@link ImsCallSessionImplBase} of the new incoming call.
@@ -1391,6 +1450,62 @@ public class MmTelFeature extends ImsFeature {
// Base implementation, no-op
}
/**
* Called by the framework to pass {@link MediaThreshold}. The MmTelFeature should override this
* method to get Media quality threshold. This will pass the consolidated threshold values from
* Telephony framework. IMS provider needs to monitor media quality of active call and notify
* media quality {@link #notifyMediaQualityStatusChanged(MediaQualityStatus)} when the measured
* media quality crosses at least one of {@link MediaThreshold} set by this.
*
* @param mediaSessionType media session type for this Threshold info.
* @param mediaThreshold media threshold information
* @hide
*/
@SystemApi
public void setMediaThreshold(
@MediaQualityStatus.MediaSessionType int mediaSessionType,
@NonNull MediaThreshold mediaThreshold) {
// Base Implementation - Should be overridden.
Log.d(LOG_TAG, "setMediaThreshold is not supported." + mediaThreshold);
}
/**
* The MmTelFeature should override this method to clear Media quality thresholds that were
* registered and stop media quality status updates.
*
* @param mediaSessionType media session type
* @hide
*/
@SystemApi
public void clearMediaThreshold(@MediaQualityStatus.MediaSessionType int mediaSessionType) {
// Base Implementation - Should be overridden.
Log.d(LOG_TAG, "clearMediaThreshold is not supported." + mediaSessionType);
}
/**
* IMS provider should override this method to return currently measured media quality status.
*
* <p/>
* If media quality status is not yet measured after call is active, it needs to notify media
* quality status {@link #notifyMediaQualityStatusChanged(MediaQualityStatus)} when the first
* measurement is done.
*
* @param mediaSessionType media session type
* @return Current media quality status. It could be null if media quality status is not
* measured yet or {@link MediaThreshold} was not set corresponding to the media session
* type.
*
* @hide
*/
@SystemApi
@Nullable
public MediaQualityStatus queryMediaQualityStatus(
@MediaQualityStatus.MediaSessionType int mediaSessionType) {
// Base Implementation - Should be overridden.
Log.d(LOG_TAG, "queryMediaQualityStatus is not supported." + mediaSessionType);
return null;
}
/**
* Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
*