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 com.android.telephony.imsmedia; 18 19 import android.os.Parcel; 20 import android.telephony.ims.RtpHeaderExtension; 21 import android.telephony.imsmedia.AudioConfig; 22 import android.telephony.imsmedia.MediaQualityThreshold; 23 24 import com.android.telephony.imsmedia.util.Log; 25 26 import java.util.List; 27 28 /** 29 * Audio session implementation for internal AP based RTP stack. This handles all API calls from 30 * applications and passes it to native library. 31 */ 32 public class AudioLocalSession { 33 private static final String TAG = "AudioLocalSession"; 34 private int mSessionId; 35 private long mNativeObject = 0; 36 37 /** 38 * Instantiates a new audio session based on AP RTP stack 39 * 40 * @param sessionId : session identifier 41 * @param nativeObject : jni object modifier for calling jni methods 42 */ AudioLocalSession(final int sessionId, final long nativeObject)43 AudioLocalSession(final int sessionId, final long nativeObject) { 44 mSessionId = sessionId; 45 mNativeObject = nativeObject; 46 } 47 48 /** Returns the unique session identifier */ getSessionId()49 public int getSessionId() { 50 Log.dc(TAG, "getSessionId"); 51 return mSessionId; 52 } 53 54 /** 55 * Send request message with the corresponding arguments to libimsmediajni library to operate 56 * 57 * @param sessionId : session identifier 58 * @param parcel : parcel argument to send to jni 59 */ sendRequest(final int sessionId, final Parcel parcel)60 public void sendRequest(final int sessionId, final Parcel parcel) { 61 if (mNativeObject != 0) { 62 if (parcel == null) return; 63 byte[] data = parcel.marshall(); 64 JNIImsMediaService.sendMessage(mNativeObject, sessionId, data); 65 parcel.recycle(); 66 } 67 } 68 69 /** 70 * Modifies the configuration of the RTP session after the session is opened. It can be used 71 * modify the direction, access network, codec parameters RTCP configuration, remote address and 72 * remote port number. The service will apply if anything changed in this invocation compared to 73 * previous and respond the updated the config in ImsMediaSession#onModifySessionResponse() API 74 * 75 * @param config provides remote end point info and codec details 76 */ modifySession(final AudioConfig config)77 public void modifySession(final AudioConfig config) { 78 Parcel parcel = Parcel.obtain(); 79 parcel.writeInt(AudioSession.CMD_MODIFY_SESSION); 80 if (config != null) { 81 config.writeToParcel(parcel, 0); 82 } 83 sendRequest(mSessionId, parcel); 84 } 85 86 /** 87 * Adds a new remote configuration to a RTP session during early media scenarios where the IMS 88 * network could add more than one remote endpoint. 89 * 90 * @param config provides remote end point info and codec details 91 */ addConfig(final AudioConfig config)92 public void addConfig(final AudioConfig config) { 93 Parcel parcel = Parcel.obtain(); 94 parcel.writeInt(AudioSession.CMD_ADD_CONFIG); 95 if (config != null) { 96 config.writeToParcel(parcel, 0); 97 } 98 sendRequest(mSessionId, parcel); 99 } 100 101 /** 102 * Deletes a remote configuration from a RTP session during early media scenarios. A session 103 * shall have at least one config so this API shall not delete the last config. 104 * 105 * @param config remote config to be deleted 106 */ deleteConfig(final AudioConfig config)107 public void deleteConfig(final AudioConfig config) { 108 Parcel parcel = Parcel.obtain(); 109 parcel.writeInt(AudioSession.CMD_DELETE_CONFIG); 110 if (config != null) { 111 config.writeToParcel(parcel, 0); 112 } 113 sendRequest(mSessionId, parcel); 114 } 115 116 /** 117 * Confirms a remote configuration for a Rtp session for early media scenarios when there are 118 * more than one remote configs. All other early remote configs (potentially including the 119 * config created as part of openSession) are auto deleted when one config is confirmed. 120 * Confirming a remote configuration is necessary only if additional configurations were 121 * created. New remote configurations cannot be added after a remote configuration is confirmed. 122 * 123 * @param config remote config to be confirmed 124 */ confirmConfig(final AudioConfig config)125 public void confirmConfig(final AudioConfig config) { 126 Parcel parcel = Parcel.obtain(); 127 parcel.writeInt(AudioSession.CMD_CONFIRM_CONFIG); 128 if (config != null) { 129 config.writeToParcel(parcel, 0); 130 } 131 sendRequest(mSessionId, parcel); 132 } 133 134 /** 135 * Send DTMF digit until the duration expires. 136 * 137 * @param dtmfDigit single char having one of 12 values: 0-9, *, # 138 * @param duration of the key press in milliseconds. 139 */ sendDtmf(final char dtmfDigit, final int duration)140 public void sendDtmf(final char dtmfDigit, final int duration) { 141 Parcel parcel = Parcel.obtain(); 142 parcel.writeInt(AudioSession.CMD_SEND_DTMF); 143 parcel.writeByte((byte)dtmfDigit); 144 parcel.writeInt(duration); 145 sendRequest(mSessionId, parcel); 146 } 147 148 /** 149 * Send RTP header extension to the other party in the next RTP packet. 150 * 151 * @param extensions List of RTP header extensions to be transmitted 152 */ sendHeaderExtension(final List<RtpHeaderExtension> extensions)153 public void sendHeaderExtension(final List<RtpHeaderExtension> extensions) { 154 Parcel parcel = Parcel.obtain(); 155 parcel.writeInt(AudioSession.CMD_SEND_RTP_HDR_EXTN); 156 parcel.writeInt(extensions.size()); 157 for (RtpHeaderExtension item : extensions) { 158 item.writeToParcel(parcel, 0); 159 } 160 sendRequest(mSessionId, parcel); 161 } 162 163 /** 164 * Sets the media quality threshold parameters of the session to get media quality 165 * notifications. 166 * 167 * @param threshold media quality thresholds for various quality parameters 168 */ setMediaQualityThreshold(final MediaQualityThreshold threshold)169 public void setMediaQualityThreshold(final MediaQualityThreshold threshold) { 170 Parcel parcel = Parcel.obtain(); 171 parcel.writeInt(AudioSession.CMD_SET_MEDIA_QUALITY_THRESHOLD); 172 if (threshold != null) { 173 threshold.writeToParcel(parcel, 0); 174 } 175 sendRequest(mSessionId, parcel); 176 } 177 178 /** 179 * Queries the current rtp reception statistics parameters for checking the current status of 180 * the rtp stream. It will trigger the notifyRtpReceptionStats() with the RtpReceptionStats. 181 * 182 * @param intervalMs The interval of the time in milliseconds of the rtp reception notification 183 */ requestRtpReceptionStats(final int intervalMs)184 public void requestRtpReceptionStats(final int intervalMs) { 185 Parcel parcel = Parcel.obtain(); 186 parcel.writeInt(AudioSession.CMD_REQUEST_RECEPTION_STATS); 187 parcel.writeInt(intervalMs); 188 sendRequest(mSessionId, parcel); 189 } 190 191 /** 192 * Adjust the delay in the jitter buffer to synchronize the audio with the time of video frames 193 * 194 * @param delayMs The delay to adjust the additional delay to the jitter buffer. The value is 195 * always positive. 196 */ adjustDelay(final int delayMs)197 public void adjustDelay(final int delayMs) { 198 Parcel parcel = Parcel.obtain(); 199 parcel.writeInt(AudioSession.CMD_ADJUST_DELAY); 200 parcel.writeInt(delayMs); 201 sendRequest(mSessionId, parcel); 202 } 203 } 204