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.imsmedia; 18 19 import android.os.Binder; 20 import android.os.IBinder; 21 import android.telephony.CallQuality; 22 import android.telephony.ims.RtpHeaderExtension; 23 import android.telephony.imsmedia.IImsAudioSession; 24 import android.telephony.imsmedia.IImsAudioSessionCallback; 25 26 import java.util.List; 27 import java.util.concurrent.Executor; 28 29 /** 30 * Audio session callback APIs 31 * 32 * @hide 33 */ 34 public class AudioSessionCallback extends ImsMediaManager.SessionCallback { 35 36 private final CallbackBinder mCallbackBinder = new CallbackBinder(this); 37 38 /** @hide */ 39 @Override getBinder()40 public IBinder getBinder() { 41 return mCallbackBinder; 42 } 43 44 /** @hide */ 45 @Override setExecutor(final Executor executor)46 public void setExecutor(final Executor executor) { 47 mCallbackBinder.setExecutor(executor); 48 } 49 50 private static class CallbackBinder extends IImsAudioSessionCallback.Stub { 51 private final AudioSessionCallback mLocalCallback; 52 private Executor mExecutor; 53 CallbackBinder(final AudioSessionCallback localCallback)54 CallbackBinder(final AudioSessionCallback localCallback) { 55 mLocalCallback = localCallback; 56 } 57 58 @Override onOpenSessionSuccess(final IImsAudioSession session)59 public void onOpenSessionSuccess(final IImsAudioSession session) { 60 if (mLocalCallback == null) return; 61 62 final long callingIdentity = Binder.clearCallingIdentity(); 63 try { 64 mExecutor.execute(() 65 -> mLocalCallback.onOpenSessionSuccess(new ImsAudioSession(session))); 66 } finally { 67 restoreCallingIdentity(callingIdentity); 68 } 69 } 70 71 @Override onOpenSessionFailure(final int error)72 public void onOpenSessionFailure(final int error) { 73 if (mLocalCallback == null) return; 74 75 final long callingIdentity = Binder.clearCallingIdentity(); 76 try { 77 mExecutor.execute(() -> mLocalCallback.onOpenSessionFailure(error)); 78 } finally { 79 restoreCallingIdentity(callingIdentity); 80 } 81 } 82 83 @Override onSessionClosed()84 public void onSessionClosed() { 85 if (mLocalCallback == null) return; 86 87 final long callingIdentity = Binder.clearCallingIdentity(); 88 try { 89 mExecutor.execute(() -> mLocalCallback.onSessionClosed()); 90 } finally { 91 restoreCallingIdentity(callingIdentity); 92 } 93 } 94 95 @Override onModifySessionResponse(final AudioConfig config, final @ImsMediaSession.SessionOperationResult int result)96 public void onModifySessionResponse(final AudioConfig config, 97 final @ImsMediaSession.SessionOperationResult int result) { 98 if (mLocalCallback == null) return; 99 100 final long callingIdentity = Binder.clearCallingIdentity(); 101 try { 102 mExecutor.execute(() -> mLocalCallback.onModifySessionResponse(config, result)); 103 } finally { 104 restoreCallingIdentity(callingIdentity); 105 } 106 } 107 108 @Override onAddConfigResponse(final AudioConfig config, final @ImsMediaSession.SessionOperationResult int result)109 public void onAddConfigResponse(final AudioConfig config, 110 final @ImsMediaSession.SessionOperationResult int result) { 111 if (mLocalCallback == null) return; 112 113 final long callingIdentity = Binder.clearCallingIdentity(); 114 try { 115 mExecutor.execute(() -> mLocalCallback.onAddConfigResponse(config, result)); 116 } finally { 117 restoreCallingIdentity(callingIdentity); 118 } 119 } 120 121 @Override onConfirmConfigResponse(final AudioConfig config, final @ImsMediaSession.SessionOperationResult int result)122 public void onConfirmConfigResponse(final AudioConfig config, 123 final @ImsMediaSession.SessionOperationResult int result) { 124 if (mLocalCallback == null) return; 125 126 final long callingIdentity = Binder.clearCallingIdentity(); 127 try { 128 mExecutor.execute(() -> mLocalCallback.onConfirmConfigResponse(config, result)); 129 } finally { 130 restoreCallingIdentity(callingIdentity); 131 } 132 } 133 134 @Override onFirstMediaPacketReceived(final AudioConfig config)135 public void onFirstMediaPacketReceived(final AudioConfig config) { 136 if (mLocalCallback == null) return; 137 138 final long callingIdentity = Binder.clearCallingIdentity(); 139 try { 140 mExecutor.execute(() -> mLocalCallback.onFirstMediaPacketReceived(config)); 141 } finally { 142 restoreCallingIdentity(callingIdentity); 143 } 144 } 145 146 @Override onHeaderExtensionReceived(final List<RtpHeaderExtension> extensions)147 public void onHeaderExtensionReceived(final List<RtpHeaderExtension> extensions){ 148 if (mLocalCallback == null) return; 149 150 final long callingIdentity = Binder.clearCallingIdentity(); 151 try { 152 mExecutor.execute(() -> mLocalCallback.onHeaderExtensionReceived(extensions)); 153 } finally { 154 restoreCallingIdentity(callingIdentity); 155 } 156 } 157 158 @Override notifyMediaQualityStatus(final MediaQualityStatus status)159 public void notifyMediaQualityStatus(final MediaQualityStatus status) { 160 if (mLocalCallback == null) return; 161 162 final long callingIdentity = Binder.clearCallingIdentity(); 163 try { 164 mExecutor.execute(() -> mLocalCallback.notifyMediaQualityStatus(status)); 165 } finally { 166 restoreCallingIdentity(callingIdentity); 167 } 168 } 169 170 @Override onCallQualityChanged(final CallQuality callQuality)171 public void onCallQualityChanged(final CallQuality callQuality) { 172 if (mLocalCallback == null) return; 173 174 final long callingIdentity = Binder.clearCallingIdentity(); 175 try { 176 mExecutor.execute(() -> mLocalCallback.onCallQualityChanged(callQuality)); 177 } finally { 178 restoreCallingIdentity(callingIdentity); 179 } 180 } 181 182 @Override triggerAnbrQuery(final AudioConfig config)183 public void triggerAnbrQuery(final AudioConfig config) { 184 if (mLocalCallback == null) return; 185 186 final long callingIdentity = Binder.clearCallingIdentity(); 187 try { 188 mExecutor.execute(() -> mLocalCallback.triggerAnbrQuery(config)); 189 } finally { 190 restoreCallingIdentity(callingIdentity); 191 } 192 } 193 194 @Override onDtmfReceived(final char dtmfDigit, final int durationMs)195 public void onDtmfReceived(final char dtmfDigit, final int durationMs) { 196 if (mLocalCallback == null) return; 197 198 final long callingIdentity = Binder.clearCallingIdentity(); 199 try { 200 mExecutor.execute(() -> mLocalCallback.onDtmfReceived(dtmfDigit, durationMs)); 201 } finally { 202 restoreCallingIdentity(callingIdentity); 203 } 204 } 205 206 @Override notifyRtpReceptionStats(final RtpReceptionStats stats)207 public void notifyRtpReceptionStats(final RtpReceptionStats stats) { 208 if (mLocalCallback == null) return; 209 210 final long callingIdentity = Binder.clearCallingIdentity(); 211 try { 212 mExecutor.execute(() -> mLocalCallback.notifyRtpReceptionStats(stats)); 213 } finally { 214 restoreCallingIdentity(callingIdentity); 215 } 216 } 217 setExecutor(final Executor executor)218 private void setExecutor(final Executor executor) { 219 mExecutor = executor; 220 } 221 } 222 223 /** 224 * Called when ImsMediaSession#modifySession() API is handled 225 * 226 * @param config The AudioConfig passed in ImsMediaSession#modifySession() 227 * @param result The result of modify session 228 */ onModifySessionResponse(final AudioConfig config, final @ImsMediaSession.SessionOperationResult int result)229 public void onModifySessionResponse(final AudioConfig config, 230 final @ImsMediaSession.SessionOperationResult int result) { 231 // Base Implementation 232 } 233 234 /** 235 * Called when ImsMediaSession#addConfig() API is handled 236 * 237 * @param config The RTP config passed in 238 * ImsMediaSession#addConfig() 239 * @param result The result of adding a configuration 240 */ onAddConfigResponse(final AudioConfig config, final @ImsMediaSession.SessionOperationResult int result)241 public void onAddConfigResponse(final AudioConfig config, 242 final @ImsMediaSession.SessionOperationResult int result) { 243 // Base Implementation 244 } 245 246 /** 247 * Called when ImsMediaSession#confirmConfig() API is handled 248 * 249 * @param config The RTP config passed in 250 * ImsMediaSession#confirmConfig() 251 * @param result The result of confirm configuration 252 */ onConfirmConfigResponse(final AudioConfig config, final @ImsMediaSession.SessionOperationResult int result)253 public void onConfirmConfigResponse(final AudioConfig config, 254 final @ImsMediaSession.SessionOperationResult int result) { 255 // Base Implementation 256 } 257 258 /** 259 * Indicates when the first Rtp media packet is received by the UE 260 * during ring back, call hold or early media scenarios. This is 261 * sent only if the packet is received on the active remote 262 * configuration. 263 * 264 * In case of early media scenarios, the implementation shall play 265 * the RTP packets from the most recently added config. 266 * 267 * @param config the remote config where media packet is received 268 */ onFirstMediaPacketReceived(final AudioConfig config)269 public void onFirstMediaPacketReceived(final AudioConfig config) { 270 // Base Implementation 271 } 272 273 /** 274 * RTP header extension received from the other party 275 * 276 * @param extensions List of received RTP header extensions 277 */ onHeaderExtensionReceived(final List<RtpHeaderExtension> extensions)278 public void onHeaderExtensionReceived(final List<RtpHeaderExtension> extensions){ 279 // Base Implementation 280 } 281 282 /** 283 * Notifies media quality status observed as per thresholds set by 284 * setMediaQualityThreshold() API 285 * 286 * @param status The object of MediaQualityStatus with the rtp and 287 * the rtcp statistics. 288 */ notifyMediaQualityStatus(final MediaQualityStatus status)289 public void notifyMediaQualityStatus(final MediaQualityStatus status) { 290 // Base Implementation 291 } 292 293 /** 294 * Notifies when a change to media quality is occurred 295 * 296 * @param callQuality The media quality statistics since last report 297 */ onCallQualityChanged(final CallQuality callQuality)298 public void onCallQualityChanged(final CallQuality callQuality) { 299 // Base Implementation 300 } 301 302 /** 303 * Notifies when ImsMedia want to query the desired bitrate to NW 304 * 305 * @param config The config containing desired bitrate and direction 306 */ triggerAnbrQuery(final AudioConfig config)307 public void triggerAnbrQuery(final AudioConfig config) { 308 // Base Implementation 309 } 310 311 /** 312 * Notifies received DTMF digit to play the tone 313 * 314 * @param dtmfDigit single char having one of 12 values: 0-9, *, # 315 * @param durationMs The duration to play the tone in milliseconds unit 316 */ onDtmfReceived(final char dtmfDigit, final int durationMs)317 public void onDtmfReceived(final char dtmfDigit, final int durationMs) { 318 // Base Implementation 319 } 320 321 /** 322 * Notifies the rtp reception parameters periodically when the requestRtpReceptionStats() is 323 * triggered with the period 324 * 325 * @param stats The rtp reception parameters 326 */ notifyRtpReceptionStats(RtpReceptionStats stats)327 public void notifyRtpReceptionStats(RtpReceptionStats stats) { 328 // Base Implementation 329 } 330 331 } 332