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.annotation.IntDef; 20 import android.net.InetAddresses; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 24 import androidx.annotation.CallSuper; 25 import androidx.annotation.NonNull; 26 import androidx.annotation.Nullable; 27 28 import java.lang.annotation.Retention; 29 import java.lang.annotation.RetentionPolicy; 30 import java.net.InetSocketAddress; 31 import java.util.Objects; 32 33 /** 34 * Class to encapsulate RTP (Real Time Protocol) configurations 35 * 36 * @hide 37 */ 38 public abstract class RtpConfig implements Parcelable { 39 public static final int TYPE_AUDIO = 0; 40 public static final int TYPE_VIDEO = 1; 41 public static final int TYPE_TEXT = 2; 42 43 /** Device neither transmits nor receives any RTP */ 44 public static final int MEDIA_DIRECTION_NO_FLOW = 0; 45 /** 46 * Device transmits outgoing RTP but but doesn't receive incoming RTP. 47 * Eg. Other party muted the call 48 */ 49 public static final int MEDIA_DIRECTION_SEND_ONLY = 1; 50 /** 51 * Device receives the incoming RTP but doesn't transmit any outgoing RTP. 52 * Eg. User muted the call 53 */ 54 public static final int MEDIA_DIRECTION_RECEIVE_ONLY = 2; 55 /** Device transmits and receives RTP in both the Directions */ 56 public static final int MEDIA_DIRECTION_SEND_RECEIVE = 3; 57 /** No RTP flow however RTCP continues to flow. Eg. HOLD */ 58 public static final int MEDIA_DIRECTION_INACTIVE = 4; 59 /* definition of uninitialized port number*/ 60 public static final int UNINITIALIZED_PORT = -1; 61 62 /** @hide */ 63 @IntDef( 64 value = { 65 MEDIA_DIRECTION_NO_FLOW, 66 MEDIA_DIRECTION_SEND_ONLY, 67 MEDIA_DIRECTION_RECEIVE_ONLY, 68 MEDIA_DIRECTION_SEND_RECEIVE, 69 MEDIA_DIRECTION_INACTIVE, 70 }) 71 @Retention(RetentionPolicy.SOURCE) 72 public @interface MediaDirection {} 73 74 private final int mType; 75 private @MediaDirection int mDirection; 76 private int mAccessNetwork; 77 @Nullable 78 private InetSocketAddress mRemoteRtpAddress; 79 @Nullable 80 private RtcpConfig mRtcpConfig; 81 private byte mDscp; 82 private byte mRxPayloadTypeNumber; 83 private byte mTxPayloadTypeNumber; 84 private byte mSamplingRateKHz; 85 /** Holds RTP parameters required to maintain RTP stream continuity */ 86 @Nullable 87 private RtpContextParams mRtpContextParams; 88 @Nullable 89 private AnbrMode mAnbrMode; 90 91 /** @hide */ RtpConfig(int type, Parcel in)92 RtpConfig(int type, Parcel in) { 93 mType = type; 94 mDirection = in.readInt(); 95 mAccessNetwork = in.readInt(); 96 mRemoteRtpAddress = readSocketAddress(in); 97 mRtcpConfig = in.readParcelable(RtcpConfig.class.getClassLoader(), RtcpConfig.class); 98 mDscp = in.readByte(); 99 mRxPayloadTypeNumber = in.readByte(); 100 mTxPayloadTypeNumber = in.readByte(); 101 mSamplingRateKHz = in.readByte(); 102 mRtpContextParams = in.readParcelable(RtpContextParams.class.getClassLoader(), 103 RtpContextParams.class); 104 mAnbrMode = in.readParcelable(AnbrMode.class.getClassLoader(), AnbrMode.class); 105 } 106 107 /** @hide **/ RtpConfig(int type, AbstractBuilder builder)108 RtpConfig(int type, AbstractBuilder builder) { 109 mType = type; 110 mDirection = builder.mDirection; 111 mAccessNetwork = builder.mAccessNetwork; 112 mRemoteRtpAddress = builder.mRemoteRtpAddress; 113 mRtcpConfig = builder.mRtcpConfig; 114 mDscp = builder.mDscp; 115 mRxPayloadTypeNumber = builder.mRxPayloadTypeNumber; 116 mTxPayloadTypeNumber = builder.mTxPayloadTypeNumber; 117 mSamplingRateKHz = builder.mSamplingRateKHz; 118 mRtpContextParams = builder.mRtpContextParams; 119 mAnbrMode = builder.mAnbrMode; 120 } 121 readSocketAddress(final Parcel in)122 private @NonNull InetSocketAddress readSocketAddress(final Parcel in) { 123 final String address = in.readString(); 124 final int port = in.readInt(); 125 if(address != null && port != UNINITIALIZED_PORT) { 126 return new InetSocketAddress( 127 InetAddresses.parseNumericAddress(address), port); 128 } 129 return null; 130 } 131 getMediaType()132 public int getMediaType() { 133 return mType; 134 } 135 getMediaDirection()136 public int getMediaDirection() { 137 return mDirection; 138 } 139 setMediaDirection(final @MediaDirection int mDirection)140 public void setMediaDirection(final @MediaDirection int mDirection) { 141 this.mDirection = mDirection; 142 } 143 getAccessNetwork()144 public int getAccessNetwork() { 145 return mAccessNetwork; 146 } 147 setAccessNetwork(final int mAccessNetwork)148 public void setAccessNetwork(final int mAccessNetwork) { 149 this.mAccessNetwork = mAccessNetwork; 150 } 151 getRemoteRtpAddress()152 public InetSocketAddress getRemoteRtpAddress() { 153 return mRemoteRtpAddress; 154 } 155 setRemoteRtpAddress(final InetSocketAddress mRemoteRtpAddress)156 public void setRemoteRtpAddress(final InetSocketAddress mRemoteRtpAddress) { 157 this.mRemoteRtpAddress = mRemoteRtpAddress; 158 } 159 getRtcpConfig()160 public RtcpConfig getRtcpConfig() { 161 return mRtcpConfig; 162 } 163 setRtcpConfig(final RtcpConfig mRtcpConfig)164 public void setRtcpConfig(final RtcpConfig mRtcpConfig) { 165 this.mRtcpConfig = mRtcpConfig; 166 } 167 getDscp()168 public byte getDscp() { 169 return mDscp; 170 } 171 setDscp(final byte mDscp)172 public void setDscp(final byte mDscp) { 173 this.mDscp = mDscp; 174 } 175 getRxPayloadTypeNumber()176 public byte getRxPayloadTypeNumber() { 177 return mRxPayloadTypeNumber; 178 } 179 setRxPayloadTypeNumber(final byte mRxPayloadTypeNumber)180 public void setRxPayloadTypeNumber(final byte mRxPayloadTypeNumber) { 181 this.mRxPayloadTypeNumber = mRxPayloadTypeNumber; 182 } 183 getTxPayloadTypeNumber()184 public byte getTxPayloadTypeNumber() { 185 return mTxPayloadTypeNumber; 186 } 187 setTxPayloadTypeNumber(final byte mTxPayloadTypeNumber)188 public void setTxPayloadTypeNumber(final byte mTxPayloadTypeNumber) { 189 this.mTxPayloadTypeNumber = mTxPayloadTypeNumber; 190 } 191 getSamplingRateKHz()192 public byte getSamplingRateKHz() { 193 return mSamplingRateKHz; 194 } 195 setSamplingRateKHz(final byte mSamplingRateKHz)196 public void setSamplingRateKHz(final byte mSamplingRateKHz) { 197 this.mSamplingRateKHz = mSamplingRateKHz; 198 } 199 getRtpContextParams()200 public RtpContextParams getRtpContextParams() { 201 return mRtpContextParams; 202 } 203 setRtpContextParams(final RtpContextParams mRtpContextParams)204 public void setRtpContextParams(final RtpContextParams mRtpContextParams) { 205 this.mRtpContextParams = mRtpContextParams; 206 } 207 getAnbrMode()208 public AnbrMode getAnbrMode() { 209 return mAnbrMode; 210 } 211 setAnbrMode(final AnbrMode mAnbrMode)212 public void setAnbrMode(final AnbrMode mAnbrMode) { 213 this.mAnbrMode = mAnbrMode; 214 } 215 216 @NonNull 217 @Override toString()218 public String toString() { 219 return "RtpConfig: {mDirection=" + mDirection 220 + ", mAccessNetwork=" + mAccessNetwork 221 + ", mRemoteRtpAddress=" + mRemoteRtpAddress 222 + ", mRtcpConfig=" + mRtcpConfig 223 + ", mDscp=" + mDscp 224 + ", mRxPayloadTypeNumber=" + mRxPayloadTypeNumber 225 + ", mTxPayloadTypeNumber=" + mTxPayloadTypeNumber 226 + ", mSamplingRateKHz=" + mSamplingRateKHz 227 + ", mRtpContextParams=" + mRtpContextParams 228 + ", mAnbrMode=" + mAnbrMode 229 + " }"; 230 } 231 232 @Override hashCode()233 public int hashCode() { 234 return Objects.hash(mDirection, mAccessNetwork, mRemoteRtpAddress, mRtcpConfig, 235 mDscp, mRxPayloadTypeNumber, mTxPayloadTypeNumber, mSamplingRateKHz, mRtpContextParams, 236 mAnbrMode); 237 } 238 239 @Override equals(@ullable Object o)240 public boolean equals(@Nullable Object o) { 241 if (o == null || !(o instanceof RtpConfig) || hashCode() != o.hashCode()) { 242 return false; 243 } 244 245 if (this == o) { 246 return true; 247 } 248 249 RtpConfig s = (RtpConfig) o; 250 251 return (mDirection == s.mDirection 252 && mAccessNetwork == s.mAccessNetwork 253 && Objects.equals(mRemoteRtpAddress, s.mRemoteRtpAddress) 254 && Objects.equals(mRtcpConfig, s.mRtcpConfig) 255 && mDscp == s.mDscp 256 && mRxPayloadTypeNumber == s.mRxPayloadTypeNumber 257 && mTxPayloadTypeNumber == s.mTxPayloadTypeNumber 258 && mSamplingRateKHz == s.mSamplingRateKHz 259 && Objects.equals(mRtpContextParams, s.mRtpContextParams) 260 && Objects.equals(mAnbrMode, s.mAnbrMode)); 261 } 262 263 /** 264 * {@link Parcelable#describeContents} 265 */ describeContents()266 public int describeContents() { 267 return 0; 268 } 269 270 /** 271 * Used by child classes for parceling. 272 * 273 * @hide 274 */ 275 @CallSuper writeToParcel(Parcel dest, int type)276 public void writeToParcel(Parcel dest, int type) { 277 dest.writeInt(type); 278 dest.writeInt(mDirection); 279 dest.writeInt(mAccessNetwork); 280 if (mRemoteRtpAddress == null) { 281 dest.writeString(null); 282 dest.writeInt(UNINITIALIZED_PORT); 283 } else { 284 dest.writeString(mRemoteRtpAddress.getAddress().getHostAddress()); 285 dest.writeInt(mRemoteRtpAddress.getPort()); 286 } 287 dest.writeParcelable(mRtcpConfig, 0); 288 dest.writeByte(mDscp); 289 dest.writeByte(mRxPayloadTypeNumber); 290 dest.writeByte(mTxPayloadTypeNumber); 291 dest.writeByte(mSamplingRateKHz); 292 dest.writeParcelable(mRtpContextParams, 0); 293 dest.writeParcelable(mAnbrMode, 0); 294 } 295 296 public static final @NonNull Parcelable.Creator<RtpConfig> 297 CREATOR = new Parcelable.Creator() { 298 public RtpConfig createFromParcel(Parcel in) { 299 int type = in.readInt(); 300 switch (type) { 301 case TYPE_AUDIO: 302 return new AudioConfig(in); 303 case TYPE_VIDEO: 304 return new VideoConfig(in); 305 case TYPE_TEXT: 306 return new TextConfig(in); 307 default: 308 throw new IllegalArgumentException("Bad Type Parcel"); 309 } 310 } 311 312 public RtpConfig[] newArray(int size) { 313 return new RtpConfig[size]; 314 } 315 }; 316 317 /** 318 * Provides a convenient way to set the fields of a {@link RtpConfig} 319 * when creating a new instance. 320 */ 321 public static abstract class AbstractBuilder<T extends AbstractBuilder<T>> { 322 private @MediaDirection int mDirection; 323 private int mAccessNetwork; 324 @Nullable 325 private InetSocketAddress mRemoteRtpAddress; 326 @Nullable 327 private RtcpConfig mRtcpConfig; 328 private byte mDscp; 329 private byte mRxPayloadTypeNumber; 330 private byte mTxPayloadTypeNumber; 331 private byte mSamplingRateKHz; 332 @Nullable 333 private RtpContextParams mRtpContextParams; 334 private AnbrMode mAnbrMode; 335 AbstractBuilder()336 AbstractBuilder() {} 337 338 /** Returns {@code this} */ self()339 abstract T self(); 340 341 /** 342 * Sets media flow direction of {@link MediaDirection} 343 * @param direction direction of media. 344 */ setMediaDirection(final @MediaDirection int direction)345 public T setMediaDirection(final @MediaDirection int direction) { 346 this.mDirection = direction; 347 return self(); 348 } 349 350 /** 351 * Sets radio access metwork type 352 * @param accessNetwork network type 353 */ setAccessNetwork(final int accessNetwork)354 public T setAccessNetwork(final int accessNetwork) { 355 this.mAccessNetwork = accessNetwork; 356 return self(); 357 } 358 359 /** 360 * Sets Ip address and port number of the other party for RTP media. 361 * @param remoteRtpAddress ip address and port form of InetSocketAddress 362 */ setRemoteRtpAddress(final InetSocketAddress remoteRtpAddress)363 public T setRemoteRtpAddress(final InetSocketAddress remoteRtpAddress) { 364 this.mRemoteRtpAddress = remoteRtpAddress; 365 return self(); 366 } 367 368 /** 369 * Sets rtcp configuration 370 * @param rtcpConfig configuration fields of a {@link RtcpConfig} 371 */ setRtcpConfig(final RtcpConfig rtcpConfig)372 public T setRtcpConfig(final RtcpConfig rtcpConfig) { 373 this.mRtcpConfig = rtcpConfig; 374 return self(); 375 } 376 377 /** 378 * Sets a dscp: Differentiated Services Field Code Point value, see RFC 2474 379 * @param dscp dscp value 380 */ setDscp(final byte dscp)381 public T setDscp(final byte dscp) { 382 this.mDscp = dscp; 383 return self(); 384 } 385 386 /** 387 * Sets static or dynamic payload type number negotiated through the SDP for 388 * the incoming RTP packets. This value shall be matched with the PT value 389 * of the incoming RTP header. Values 0 to 127, see RFC 3551 section 6. 390 * @param rxPayloadTypeNumber payload type number. 391 */ setRxPayloadTypeNumber(final byte rxPayloadTypeNumber)392 public T setRxPayloadTypeNumber(final byte rxPayloadTypeNumber) { 393 this.mRxPayloadTypeNumber = rxPayloadTypeNumber; 394 return self(); 395 } 396 397 /** 398 * Sets static or dynamic payload type number negotiated through the SDP for 399 * the outgoing RTP packets. This value shall be set to the PT value 400 * of the outgoing RTP header. Values 0 to 127, see RFC 3551 section 6. 401 * @param txPayloadTypeNumber payload type number. 402 */ setTxPayloadTypeNumber(final byte txPayloadTypeNumber)403 public T setTxPayloadTypeNumber(final byte txPayloadTypeNumber) { 404 this.mTxPayloadTypeNumber = txPayloadTypeNumber; 405 return self(); 406 } 407 408 /** 409 * Sets media source sampling rate in kHz. 410 * @param samplingRateKHz sampling rate. 411 */ setSamplingRateKHz(final byte samplingRateKHz)412 public T setSamplingRateKHz(final byte samplingRateKHz) { 413 this.mSamplingRateKHz = samplingRateKHz; 414 return self(); 415 } 416 417 /** 418 * Sets RTP parameters required for RTP context transfer 419 * @param rtpContextParams parameter fields of a {@link RtpContextParams} 420 */ setRtpContextParams(final RtpContextParams rtpContextParams)421 public T setRtpContextParams(final RtpContextParams rtpContextParams) { 422 this.mRtpContextParams = rtpContextParams; 423 return self(); 424 } 425 426 /** 427 * Sets AnbrMode information 428 * @param anbrMode The codec mode of the current negotiated codec (either Evs or Amr) 429 */ setAnbrMode(final AnbrMode anbrMode)430 public T setAnbrMode(final AnbrMode anbrMode) { 431 this.mAnbrMode = anbrMode; 432 return self(); 433 } 434 } 435 } 436