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.hardware.radio.ims.media.CodecParams; 20 import android.hardware.radio.ims.media.CodecSpecificParams; 21 import android.hardware.radio.ims.media.DtmfParams; 22 import android.hardware.radio.ims.media.RtpAddress; 23 import android.hardware.radio.ims.media.RtpSessionParams; 24 import android.net.InetAddresses; 25 import android.os.Handler; 26 import android.os.Message; 27 import android.os.ParcelFileDescriptor; 28 import android.telephony.CallQuality; 29 import android.telephony.ims.RtpHeaderExtension; 30 import android.telephony.imsmedia.AmrParams; 31 import android.telephony.imsmedia.AudioConfig; 32 import android.telephony.imsmedia.EvsParams; 33 import android.telephony.imsmedia.MediaQualityStatus; 34 import android.telephony.imsmedia.MediaQualityThreshold; 35 import android.telephony.imsmedia.RtcpConfig; 36 import android.telephony.imsmedia.RtpConfig; 37 38 import com.android.telephony.imsmedia.ImsMediaController.OpenSessionCallback; 39 40 import java.net.InetSocketAddress; 41 import java.util.Arrays; 42 43 /** 44 * Class consists of utility methods and sub classes 45 * 46 * @hide 47 */ 48 public final class Utils { 49 50 static final int UNUSED = -1; 51 52 /** Class to encapsulate open session parameters */ 53 static final class OpenSessionParams { 54 private final ParcelFileDescriptor rtpFd; 55 private final ParcelFileDescriptor rtcpFd; 56 private final RtpConfig rtpConfig; 57 private final OpenSessionCallback callback; 58 OpenSessionParams(final ParcelFileDescriptor rtpFd, final ParcelFileDescriptor rtcpFd, final RtpConfig rtpConfig, final OpenSessionCallback callback)59 OpenSessionParams(final ParcelFileDescriptor rtpFd, 60 final ParcelFileDescriptor rtcpFd, 61 final RtpConfig rtpConfig, 62 final OpenSessionCallback callback) { 63 this.rtpFd = rtpFd; 64 this.rtcpFd = rtcpFd; 65 this.rtpConfig = rtpConfig; 66 this.callback = callback; 67 } 68 getRtpFd()69 ParcelFileDescriptor getRtpFd() { 70 return rtpFd; 71 } 72 getRtcpFd()73 ParcelFileDescriptor getRtcpFd() { 74 return rtcpFd; 75 } 76 getRtpConfig()77 RtpConfig getRtpConfig() { 78 return rtpConfig; 79 } 80 getCallback()81 OpenSessionCallback getCallback() { 82 return callback; 83 } 84 } 85 sendMessage(final Handler handler, final int command)86 static void sendMessage(final Handler handler, final int command) { 87 final Message msg = handler.obtainMessage(command); 88 msg.sendToTarget(); 89 } 90 sendMessage(final Handler handler, final int command, final Object argument)91 static void sendMessage(final Handler handler, final int command, final Object argument) { 92 final Message msg = handler.obtainMessage(command, argument); 93 msg.sendToTarget(); 94 } 95 sendMessage(final Handler handler, final int command, final int arg1, final int arg2)96 static void sendMessage(final Handler handler, 97 final int command, final int arg1, final int arg2) { 98 final Message msg = handler.obtainMessage(command, arg1, arg2); 99 msg.sendToTarget(); 100 } 101 sendMessage(final Handler handler, final int command, final int arg1, final int arg2, final Object object)102 static void sendMessage(final Handler handler, final int command, 103 final int arg1, final int arg2, final Object object) { 104 final Message msg = handler.obtainMessage(command, arg1, arg2, object); 105 msg.sendToTarget(); 106 } 107 buildRtpAddress(final AudioConfig audioConfig)108 private static RtpAddress buildRtpAddress(final AudioConfig audioConfig) { 109 final RtpAddress addr = new RtpAddress(); 110 111 addr.ipAddress = audioConfig.getRemoteRtpAddress().getAddress().getHostAddress(); 112 addr.portNumber = audioConfig.getRemoteRtpAddress().getPort(); 113 114 return addr; 115 } 116 buildDtmfParams(final AudioConfig audioConfig)117 private static DtmfParams buildDtmfParams(final AudioConfig audioConfig) { 118 final DtmfParams dtmfParams = new DtmfParams(); 119 120 dtmfParams.txPayloadTypeNumber = audioConfig.getTxDtmfPayloadTypeNumber(); 121 dtmfParams.rxPayloadTypeNumber = audioConfig.getRxDtmfPayloadTypeNumber(); 122 dtmfParams.samplingRateKHz = audioConfig.getDtmfSamplingRateKHz(); 123 124 return dtmfParams; 125 } 126 127 private static android.hardware.radio.ims.media.AmrParams buildAmrParams(final AudioConfig audioConfig)128 buildAmrParams(final AudioConfig audioConfig) { 129 final android.hardware.radio.ims.media.AmrParams amrParams = 130 new android.hardware.radio.ims.media.AmrParams(); 131 132 amrParams.amrMode = audioConfig.getAmrParams().getAmrMode(); 133 amrParams.octetAligned = audioConfig.getAmrParams().getOctetAligned(); 134 amrParams.maxRedundancyMillis = audioConfig.getAmrParams().getMaxRedundancyMillis(); 135 136 return amrParams; 137 } 138 139 private static android.hardware.radio.ims.media.EvsParams buildEvsParams(final AudioConfig audioConfig)140 buildEvsParams(final AudioConfig audioConfig) { 141 final android.hardware.radio.ims.media.EvsParams evsParams = 142 new android.hardware.radio.ims.media.EvsParams(); 143 144 evsParams.bandwidth = audioConfig.getEvsParams().getEvsBandwidth(); 145 evsParams.evsMode = audioConfig.getEvsParams().getEvsMode(); 146 evsParams.channelAwareMode = audioConfig.getEvsParams().getChannelAwareMode(); 147 evsParams.useHeaderFullOnly = 148 audioConfig.getEvsParams().getUseHeaderFullOnly(); 149 evsParams.codecModeRequest = audioConfig.getEvsParams().getCodecModeRequest(); 150 151 return evsParams; 152 } 153 buildCodecParams(final AudioConfig audioConfig)154 private static CodecParams buildCodecParams(final AudioConfig audioConfig) { 155 final CodecParams codecParams = new CodecParams(); 156 157 codecParams.codecType = audioConfig.getCodecType(); 158 codecParams.rxPayloadTypeNumber = audioConfig.getRxPayloadTypeNumber(); 159 codecParams.txPayloadTypeNumber = audioConfig.getTxPayloadTypeNumber(); 160 codecParams.samplingRateKHz = audioConfig.getSamplingRateKHz(); 161 codecParams.dtxEnabled = audioConfig.getDtxEnabled(); 162 163 if (audioConfig.getCodecType() == AudioConfig.CODEC_AMR 164 || audioConfig.getCodecType() == AudioConfig.CODEC_AMR_WB) { 165 codecParams.codecSpecificParams = new CodecSpecificParams(); 166 codecParams.codecSpecificParams.setAmr(buildAmrParams(audioConfig)); 167 } else if (audioConfig.getCodecType() == AudioConfig.CODEC_EVS) { 168 codecParams.codecSpecificParams = new CodecSpecificParams(); 169 codecParams.codecSpecificParams.setEvs(buildEvsParams(audioConfig)); 170 } 171 172 return codecParams; 173 } 174 buildSessionParams(final AudioConfig audioConfig)175 private static RtpSessionParams buildSessionParams(final AudioConfig audioConfig) { 176 final RtpSessionParams sessionParams = new RtpSessionParams(); 177 178 sessionParams.pTimeMillis = audioConfig.getPtimeMillis(); 179 sessionParams.maxPtimeMillis = audioConfig.getMaxPtimeMillis(); 180 sessionParams.dscp = audioConfig.getDscp(); 181 sessionParams.dtmfParams = buildDtmfParams(audioConfig); 182 sessionParams.codecParams = buildCodecParams(audioConfig); 183 184 return sessionParams; 185 } 186 187 private static android.hardware.radio.ims.media.RtcpConfig buildRtcpConfig(final AudioConfig audioConfig)188 buildRtcpConfig(final AudioConfig audioConfig) { 189 final android.hardware.radio.ims.media.RtcpConfig rtcpConfig = 190 new android.hardware.radio.ims.media.RtcpConfig(); 191 192 rtcpConfig.canonicalName = audioConfig.getRtcpConfig().getCanonicalName(); 193 rtcpConfig.transmitPort = audioConfig.getRtcpConfig().getTransmitPort(); 194 rtcpConfig.transmitIntervalSec = audioConfig.getRtcpConfig().getIntervalSec(); 195 rtcpConfig.rtcpXrBlocks = audioConfig.getRtcpConfig().getRtcpXrBlockTypes(); 196 197 return rtcpConfig; 198 } 199 200 /** Converts {@link AudioConfig} to HAL RtpConfig */ convertToRtpConfig( final AudioConfig audioConfig)201 public static android.hardware.radio.ims.media.RtpConfig convertToRtpConfig( 202 final AudioConfig audioConfig) { 203 final android.hardware.radio.ims.media.RtpConfig rtpConfig; 204 205 if (audioConfig == null) { 206 rtpConfig = null; 207 } else { 208 rtpConfig = new android.hardware.radio.ims.media.RtpConfig(); 209 rtpConfig.direction = audioConfig.getMediaDirection(); 210 rtpConfig.accessNetwork = audioConfig.getAccessNetwork(); 211 rtpConfig.remoteAddress = buildRtpAddress(audioConfig); 212 rtpConfig.sessionParams = buildSessionParams(audioConfig); 213 rtpConfig.rtcpConfig = buildRtcpConfig(audioConfig); 214 } 215 216 return rtpConfig; 217 } 218 219 /** Converts {@link MediaQuailtyStatus} to HAL MediaQuailtyStatus */ 220 public static android.hardware.radio.ims.media.MediaQualityStatus convertToHalMediaQualityStatus(final MediaQualityStatus status)221 convertToHalMediaQualityStatus(final MediaQualityStatus status) { 222 final android.hardware.radio.ims.media.MediaQualityStatus halStatus = 223 new android.hardware.radio.ims.media.MediaQualityStatus(); 224 halStatus.rtpInactivityTimeMillis = status.getRtpInactivityTimeMillis(); 225 halStatus.rtcpInactivityTimeMillis = status.getRtcpInactivityTimeMillis(); 226 halStatus.rtpPacketLossRate = status.getRtpPacketLossRate(); 227 halStatus.rtpJitterMillis = status.getRtpJitterMillis(); 228 return halStatus; 229 } 230 buildRtcpConfig( final android.hardware.radio.ims.media.RtpConfig rtpConfig)231 private static RtcpConfig buildRtcpConfig( 232 final android.hardware.radio.ims.media.RtpConfig rtpConfig) { 233 final RtcpConfig rtcpConfig; 234 235 if (rtpConfig.rtcpConfig == null) { 236 rtcpConfig = null; 237 } else { 238 rtcpConfig = new RtcpConfig.Builder() 239 .setCanonicalName(rtpConfig.rtcpConfig.canonicalName) 240 .setTransmitPort(rtpConfig.rtcpConfig.transmitPort) 241 .setIntervalSec(rtpConfig.rtcpConfig.transmitIntervalSec) 242 .setRtcpXrBlockTypes(rtpConfig.rtcpConfig.rtcpXrBlocks) 243 .build(); 244 } 245 246 return rtcpConfig; 247 } 248 buildEvsParams( final android.hardware.radio.ims.media.RtpConfig rtpConfig)249 private static EvsParams buildEvsParams( 250 final android.hardware.radio.ims.media.RtpConfig rtpConfig) { 251 final EvsParams evsParams; 252 253 if (rtpConfig == null 254 || rtpConfig.sessionParams == null 255 || rtpConfig.sessionParams.codecParams == null 256 || rtpConfig.sessionParams.codecParams.codecSpecificParams == null 257 || rtpConfig.sessionParams.codecParams.codecSpecificParams.getTag() 258 != CodecSpecificParams.evs) { 259 evsParams = null; 260 } else { 261 final android.hardware.radio.ims.media.EvsParams evs = 262 rtpConfig.sessionParams.codecParams.codecSpecificParams.getEvs(); 263 evsParams = new EvsParams.Builder() 264 .setEvsbandwidth(evs.bandwidth) 265 .setEvsMode(evs.evsMode) 266 .setChannelAwareMode(evs.channelAwareMode) 267 .setHeaderFullOnly(evs.useHeaderFullOnly) 268 .setCodecModeRequest(evs.codecModeRequest) 269 .build(); 270 } 271 272 return evsParams; 273 } 274 buildAmrParams( final android.hardware.radio.ims.media.RtpConfig rtpConfig)275 private static AmrParams buildAmrParams( 276 final android.hardware.radio.ims.media.RtpConfig rtpConfig) { 277 final AmrParams amrParams; 278 279 if (rtpConfig == null 280 || rtpConfig.sessionParams == null 281 || rtpConfig.sessionParams.codecParams == null 282 || rtpConfig.sessionParams.codecParams.codecSpecificParams == null 283 || rtpConfig.sessionParams.codecParams.codecSpecificParams.getTag() 284 != CodecSpecificParams.amr) { 285 amrParams = null; 286 } else { 287 final android.hardware.radio.ims.media.AmrParams amr = 288 rtpConfig.sessionParams.codecParams.codecSpecificParams.getAmr(); 289 amrParams = new AmrParams.Builder() 290 .setAmrMode(amr.amrMode) 291 .setOctetAligned(amr.octetAligned) 292 .setMaxRedundancyMillis(amr.maxRedundancyMillis) 293 .build(); 294 } 295 296 return amrParams; 297 } 298 buildRtpAddress( final android.hardware.radio.ims.media.RtpConfig rtpConfig)299 private static InetSocketAddress buildRtpAddress( 300 final android.hardware.radio.ims.media.RtpConfig rtpConfig) { 301 final InetSocketAddress rtpAddress; 302 303 if (rtpConfig.remoteAddress == null) { 304 rtpAddress = null; 305 } else { 306 rtpAddress = new InetSocketAddress( 307 InetAddresses.parseNumericAddress(rtpConfig.remoteAddress.ipAddress), 308 rtpConfig.remoteAddress.portNumber); 309 } 310 311 return rtpAddress; 312 } 313 314 /** Converts HAL RtpConfig to AudioConfig */ convertToAudioConfig( final android.hardware.radio.ims.media.RtpConfig rtpConfig)315 public static AudioConfig convertToAudioConfig( 316 final android.hardware.radio.ims.media.RtpConfig rtpConfig) { 317 final AudioConfig audioConfig; 318 319 if (rtpConfig == null) { 320 audioConfig = null; 321 } else { 322 audioConfig = new AudioConfig.Builder() 323 .setMediaDirection(rtpConfig.direction) 324 .setAccessNetwork(rtpConfig.accessNetwork) 325 .setRemoteRtpAddress(buildRtpAddress(rtpConfig)) 326 .setRtcpConfig(buildRtcpConfig(rtpConfig)) 327 .setEvsParams(buildEvsParams(rtpConfig)) 328 .setAmrParams(buildAmrParams(rtpConfig)) 329 .build(); 330 331 /** Populate session related parameters if present */ 332 if (rtpConfig.sessionParams != null) { 333 audioConfig.setDscp(rtpConfig.sessionParams.dscp); 334 audioConfig.setPtimeMillis(rtpConfig.sessionParams.pTimeMillis); 335 audioConfig.setMaxPtimeMillis(rtpConfig.sessionParams.maxPtimeMillis); 336 337 /** Populate DTMF parameter */ 338 final DtmfParams dtmfParams = rtpConfig.sessionParams.dtmfParams; 339 if (dtmfParams != null) { 340 audioConfig.setTxDtmfPayloadTypeNumber(dtmfParams.txPayloadTypeNumber); 341 audioConfig.setRxDtmfPayloadTypeNumber(dtmfParams.rxPayloadTypeNumber); 342 audioConfig.setDtmfSamplingRateKHz(dtmfParams.samplingRateKHz); 343 } 344 345 /** Populate codec parameters */ 346 final CodecParams codecParams = rtpConfig.sessionParams.codecParams; 347 if (codecParams != null) { 348 audioConfig.setCodecType(codecParams.codecType); 349 audioConfig.setRxPayloadTypeNumber(codecParams.rxPayloadTypeNumber); 350 audioConfig.setTxPayloadTypeNumber(codecParams.txPayloadTypeNumber); 351 audioConfig.setSamplingRateKHz(codecParams.samplingRateKHz); 352 audioConfig.setDtxEnabled(codecParams.dtxEnabled); 353 } 354 } 355 } 356 357 return audioConfig; 358 } 359 360 /** Converts {@link MediaQualityThreshold} to HAL MediaQualityThreshold */ 361 public static android.hardware.radio.ims.media.MediaQualityThreshold convertMediaQualityThreshold(final MediaQualityThreshold in)362 convertMediaQualityThreshold(final MediaQualityThreshold in) { 363 final android.hardware.radio.ims.media.MediaQualityThreshold out; 364 365 if (in == null) { 366 out = null; 367 } else { 368 out = new android.hardware.radio.ims.media.MediaQualityThreshold(); 369 out.rtpInactivityTimerMillis = Arrays.copyOf(in.getRtpInactivityTimerMillis(), 370 in.getRtpInactivityTimerMillis().length); 371 out.rtcpInactivityTimerMillis = in.getRtcpInactivityTimerMillis(); 372 out.rtpHysteresisTimeInMillis = in.getRtpHysteresisTimeInMillis(); 373 out.rtpPacketLossDurationMillis = in.getRtpPacketLossDurationMillis(); 374 out.rtpPacketLossRate = Arrays.copyOf(in.getRtpPacketLossRate(), 375 in.getRtpPacketLossRate().length); 376 out.rtpJitterMillis = Arrays.copyOf(in.getRtpJitterMillis(), 377 in.getRtpJitterMillis().length); 378 out.notifyCurrentStatus = in.getNotifyCurrentStatus(); 379 } 380 381 return out; 382 } 383 384 /** Converts HAL MediaQualityThreshold to {@link MediaQualityThreshold} */ convertMediaQualityThreshold( final android.hardware.radio.ims.media.MediaQualityThreshold in)385 public static MediaQualityThreshold convertMediaQualityThreshold( 386 final android.hardware.radio.ims.media.MediaQualityThreshold in) { 387 return (in == null) ? null : new MediaQualityThreshold.Builder() 388 .setRtpInactivityTimerMillis(in.rtpInactivityTimerMillis) 389 .setRtcpInactivityTimerMillis(in.rtcpInactivityTimerMillis) 390 .setRtpHysteresisTimeInMillis(in.rtpHysteresisTimeInMillis) 391 .setRtpPacketLossDurationMillis(in.rtpPacketLossDurationMillis) 392 .setRtpPacketLossRate(in.rtpPacketLossRate) 393 .setRtpJitterMillis(in.rtpJitterMillis) 394 .setNotifyCurrentStatus(in.notifyCurrentStatus) 395 .setVideoBitrateBps(0) 396 .build(); 397 } 398 399 /** Converts HAL MediaQualityStatus to {@link MediaQualityStatus} */ convertMediaQualityStatus( final android.hardware.radio.ims.media.MediaQualityStatus in)400 public static MediaQualityStatus convertMediaQualityStatus( 401 final android.hardware.radio.ims.media.MediaQualityStatus in) { 402 return (in == null) ? null : new MediaQualityStatus.Builder() 403 .setRtpInactivityTimeMillis(in.rtpInactivityTimeMillis) 404 .setRtcpInactivityTimeMillis(in.rtcpInactivityTimeMillis) 405 .setRtpPacketLossRate(in.rtpPacketLossRate) 406 .setRtpJitterMillis(in.rtpJitterMillis) 407 .build(); 408 } 409 410 public static android.hardware.radio.ims.media.RtpHeaderExtension convertRtpHeaderExtension(final RtpHeaderExtension in)411 convertRtpHeaderExtension(final RtpHeaderExtension in) { 412 final android.hardware.radio.ims.media.RtpHeaderExtension out; 413 414 if (in == null) { 415 out = null; 416 } else { 417 out = new android.hardware.radio.ims.media.RtpHeaderExtension(); 418 out.localId = in.getLocalIdentifier(); 419 out.data = in.getExtensionData(); 420 } 421 422 return out; 423 } 424 convertRtpHeaderExtension( final android.hardware.radio.ims.media.RtpHeaderExtension in)425 public static RtpHeaderExtension convertRtpHeaderExtension( 426 final android.hardware.radio.ims.media.RtpHeaderExtension in) { 427 return (in == null) ? null : new RtpHeaderExtension(in.localId, in.data); 428 } 429 430 /** Converts HAL CallQuality to {@link CallQuality} */ convertCallQuality( final android.hardware.radio.ims.media.CallQuality in)431 public static CallQuality convertCallQuality( 432 final android.hardware.radio.ims.media.CallQuality in) { 433 return (in == null) ? null : new CallQuality.Builder() 434 .setDownlinkCallQualityLevel(in.downlinkCallQualityLevel) 435 .setUplinkCallQualityLevel(in.uplinkCallQualityLevel) 436 .setCallDurationMillis(in.callDuration) 437 .setNumRtpPacketsTransmitted(in.numRtpPacketsTransmitted) 438 .setNumRtpPacketsReceived(in.numRtpPacketsReceived) 439 .setNumRtpPacketsTransmittedLost(in.numRtpPacketsTransmittedLost) 440 .setNumRtpPacketsNotReceived(in.numRtpPacketsNotReceived) 441 .setAverageRelativeJitter(in.averageRelativeJitter) 442 .setMaxRelativeJitter(in.maxRelativeJitter) 443 .setAverageRoundTripTimeMillis(in.averageRoundTripTime) 444 .setCodecType(in.codecType) 445 .setRtpInactivityDetected(in.rtpInactivityDetected) 446 .setIncomingSilenceDetectedAtCallSetup(in.rxSilenceDetected) 447 .setOutgoingSilenceDetectedAtCallSetup(in.txSilenceDetected) 448 .setNumVoiceFrames(in.numVoiceFrames) 449 .setNumNoDataFrames(in.numNoDataFrames) 450 .setNumDroppedRtpPackets(in.numDroppedRtpPackets) 451 .setMinPlayoutDelayMillis(in.minPlayoutDelayMillis) 452 .setMaxPlayoutDelayMillis(in.maxPlayoutDelayMillis) 453 .setNumRtpSidPacketsReceived(in.numRtpSidPacketsReceived) 454 .setNumRtpDuplicatePackets(in.numRtpDuplicatePackets) 455 .build(); 456 } 457 } 458