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.os.Parcel;
21 import android.os.Parcelable;
22 
23 import androidx.annotation.NonNull;
24 import androidx.annotation.Nullable;
25 
26 import java.lang.annotation.Retention;
27 import java.lang.annotation.RetentionPolicy;
28 import java.util.Objects;
29 
30 /**
31  * The class represents RTP (Real Time Control) configuration for audio stream.
32  *
33  * @hide
34  */
35 public final class AudioConfig extends RtpConfig {
36     /** Adaptive Multi-Rate */
37     public static final int CODEC_AMR = android.hardware.radio.ims.media.CodecType.AMR;
38     /** Adaptive Multi-Rate Wide Band */
39     public static final int CODEC_AMR_WB = android.hardware.radio.ims.media.CodecType.AMR_WB;
40     /** Enhanced Voice Services */
41     public static final int CODEC_EVS = android.hardware.radio.ims.media.CodecType.EVS;
42     /** G.711 A-law i.e. Pulse Code Modulation using A-law */
43     public static final int CODEC_PCMA = android.hardware.radio.ims.media.CodecType.PCMA;
44     /** G.711 μ-law i.e. Pulse Code Modulation using μ-law */
45     public static final int CODEC_PCMU = android.hardware.radio.ims.media.CodecType.PCMU;
46 
47     /** @hide */
48     @IntDef(
49         flag = true,
50         value = {
51            CODEC_AMR,
52            CODEC_AMR_WB,
53            CODEC_EVS,
54            CODEC_PCMA,
55            CODEC_PCMU,
56     })
57     @Retention(RetentionPolicy.SOURCE)
58     public @interface CodecType {}
59 
60     private byte pTimeMillis;
61     private int maxPtimeMillis;
62     private boolean dtxEnabled;
63     private @CodecType int codecType;
64     private byte mDtmfTxPayloadTypeNumber;
65     private byte mDtmfRxPayloadTypeNumber;
66     private byte dtmfSamplingRateKHz;
67     @Nullable
68     private AmrParams amrParams;
69     @Nullable
70     private EvsParams evsParams;
71 
72     /** @hide */
AudioConfig(Parcel in)73     AudioConfig(Parcel in) {
74         super(RtpConfig.TYPE_AUDIO, in);
75         pTimeMillis = in.readByte();
76         maxPtimeMillis = in.readInt();
77         dtxEnabled = in.readBoolean();
78         codecType = in.readInt();
79         mDtmfTxPayloadTypeNumber = in.readByte();
80         mDtmfRxPayloadTypeNumber = in.readByte();
81         dtmfSamplingRateKHz = in.readByte();
82         amrParams = in.readParcelable(AmrParams.class.getClassLoader(), AmrParams.class);
83         evsParams = in.readParcelable(EvsParams.class.getClassLoader(), EvsParams.class);
84     }
85 
86     /** @hide */
AudioConfig(Builder builder)87     AudioConfig(Builder builder) {
88         super(RtpConfig.TYPE_AUDIO, builder);
89         this.pTimeMillis = builder.pTimeMillis;
90         this.maxPtimeMillis = builder.maxPtimeMillis;
91         this.dtxEnabled = builder.dtxEnabled;
92         this.codecType = builder.codecType;
93         this.mDtmfTxPayloadTypeNumber = builder.mDtmfTxPayloadTypeNumber;
94         this.mDtmfRxPayloadTypeNumber = builder.mDtmfRxPayloadTypeNumber;
95         this.dtmfSamplingRateKHz = builder.dtmfSamplingRateKHz;
96         this.amrParams = builder.amrParams;
97         this.evsParams = builder.evsParams;
98     }
99 
100     /** @hide **/
getPtimeMillis()101     public byte getPtimeMillis() {
102         return pTimeMillis;
103     }
104 
105     /** @hide **/
setPtimeMillis(byte pTimeMillis)106     public void setPtimeMillis(byte pTimeMillis) {
107         this.pTimeMillis = pTimeMillis;
108     }
109 
110     /** @hide **/
getMaxPtimeMillis()111     public int getMaxPtimeMillis() {
112         return maxPtimeMillis;
113     }
114 
115     /** @hide **/
setMaxPtimeMillis(int maxPtimeMillis)116     public void setMaxPtimeMillis(int maxPtimeMillis) {
117         this.maxPtimeMillis = maxPtimeMillis;
118     }
119 
120     /** @hide **/
getDtxEnabled()121     public boolean getDtxEnabled() {
122         return dtxEnabled;
123     }
124 
125     /** @hide **/
setDtxEnabled(boolean dtxEnabled)126     public void setDtxEnabled(boolean dtxEnabled) {
127         this.dtxEnabled = dtxEnabled;
128     }
129 
130     /** @hide **/
getCodecType()131     public int getCodecType() {
132         return codecType;
133     }
134 
135     /** @hide **/
setCodecType(int codecType)136     public void setCodecType(int codecType) {
137         this.codecType = codecType;
138     }
139 
140     /** @hide **/
getTxDtmfPayloadTypeNumber()141     public byte getTxDtmfPayloadTypeNumber() {
142         return mDtmfTxPayloadTypeNumber;
143     }
144 
145     /** @hide **/
getRxDtmfPayloadTypeNumber()146     public byte getRxDtmfPayloadTypeNumber() {
147         return mDtmfRxPayloadTypeNumber;
148     }
149 
150     /** @hide **/
setTxDtmfPayloadTypeNumber(byte dtmfTxPayloadTypeNumber)151     public void setTxDtmfPayloadTypeNumber(byte dtmfTxPayloadTypeNumber) {
152         this.mDtmfTxPayloadTypeNumber = dtmfTxPayloadTypeNumber;
153     }
154 
155     /** @hide **/
setRxDtmfPayloadTypeNumber(byte dtmfRxPayloadTypeNumber)156     public void setRxDtmfPayloadTypeNumber(byte dtmfRxPayloadTypeNumber) {
157         this.mDtmfRxPayloadTypeNumber = dtmfRxPayloadTypeNumber;
158     }
159 
160     /** @hide **/
getDtmfSamplingRateKHz()161     public byte getDtmfSamplingRateKHz() {
162         return dtmfSamplingRateKHz;
163     }
164 
165     /** @hide **/
setDtmfSamplingRateKHz(byte dtmfSamplingRateKHz)166     public void setDtmfSamplingRateKHz(byte dtmfSamplingRateKHz) {
167         this.dtmfSamplingRateKHz = dtmfSamplingRateKHz;
168     }
169 
170     /** @hide **/
getAmrParams()171     public AmrParams getAmrParams() {
172         return amrParams;
173     }
174 
175     /** @hide **/
getEvsParams()176     public EvsParams getEvsParams() {
177         return evsParams;
178     }
179 
180     @NonNull
181     @Override
toString()182     public String toString() {
183         return super.toString() + " AudioConfig: {pTimeMillis=" + pTimeMillis
184                 + ", maxPtimeMillis=" + maxPtimeMillis
185                 + ", dtxEnabled=" + dtxEnabled
186                 + ", codecType=" + codecType
187                 + ", mDtmfTxPayloadTypeNumber=" + mDtmfTxPayloadTypeNumber
188                 + ", mDtmfRxPayloadTypeNumber=" + mDtmfRxPayloadTypeNumber
189                 + ", dtmfSamplingRateKHz=" + dtmfSamplingRateKHz
190                 + ", amrParams=" + amrParams
191                 + ", evsParams=" + evsParams
192                 + " }";
193     }
194 
195     @Override
hashCode()196     public int hashCode() {
197         return Objects.hash(super.hashCode(), pTimeMillis, maxPtimeMillis,
198                 dtxEnabled, codecType, mDtmfTxPayloadTypeNumber,
199                 mDtmfRxPayloadTypeNumber, dtmfSamplingRateKHz, amrParams, evsParams);
200     }
201 
202     @Override
equals(@ullable Object o)203     public boolean equals(@Nullable Object o) {
204         if (o == null || !(o instanceof AudioConfig) || hashCode() != o.hashCode()) {
205             return false;
206         }
207 
208         if (this == o) {
209             return true;
210         }
211 
212         AudioConfig s = (AudioConfig) o;
213 
214         if (!super.equals(s)) {
215             return false;
216         }
217 
218         return (pTimeMillis == s.pTimeMillis
219                 && maxPtimeMillis == s.maxPtimeMillis
220                 && dtxEnabled == s.dtxEnabled
221                 && codecType == s.codecType
222                 && mDtmfTxPayloadTypeNumber == s.mDtmfTxPayloadTypeNumber
223                 && mDtmfRxPayloadTypeNumber == s.mDtmfRxPayloadTypeNumber
224                 && dtmfSamplingRateKHz == s.dtmfSamplingRateKHz
225                 && Objects.equals(amrParams, s.amrParams)
226                 && Objects.equals(evsParams, s.evsParams));
227     }
228 
229     /**
230      * {@link Parcelable#describeContents}
231      */
describeContents()232     public int describeContents() {
233         return 0;
234     }
235 
236     /**
237      * {@link Parcelable#writeToParcel}
238      */
writeToParcel(Parcel dest, int flags)239     public void writeToParcel(Parcel dest, int flags) {
240         super.writeToParcel(dest, RtpConfig.TYPE_AUDIO);
241         dest.writeByte(pTimeMillis);
242         dest.writeInt(maxPtimeMillis);
243         dest.writeBoolean(dtxEnabled);
244         dest.writeInt(codecType);
245         dest.writeByte(mDtmfTxPayloadTypeNumber);
246         dest.writeByte(mDtmfRxPayloadTypeNumber);
247         dest.writeByte(dtmfSamplingRateKHz);
248         dest.writeParcelable(amrParams, 0);
249         dest.writeParcelable(evsParams, 0);
250     }
251 
252     public static final @NonNull Parcelable.Creator<AudioConfig>
253             CREATOR = new Parcelable.Creator() {
254                 public AudioConfig createFromParcel(Parcel in) {
255                     in.readInt();   //skip
256                     return new AudioConfig(in);
257                 }
258 
259                 public AudioConfig[] newArray(int size) {
260                     return new AudioConfig[size];
261                 }
262             };
263 
264     /**
265      * Provides a convenient way to set the fields of a {@link AudioConfig}
266      * when creating a new instance.
267      */
268     public static final class Builder extends RtpConfig.AbstractBuilder<Builder> {
269         private byte pTimeMillis;
270         private int maxPtimeMillis;
271         private boolean dtxEnabled;
272         private @CodecType int codecType;
273         private byte mDtmfTxPayloadTypeNumber;
274         private byte mDtmfRxPayloadTypeNumber;
275         private byte dtmfSamplingRateKHz;
276         @Nullable
277         private AmrParams amrParams;
278         @Nullable
279         private EvsParams evsParams;
280 
281         /**
282          * Default constructor for Builder.
283          */
Builder()284         public Builder() {
285         }
286 
287         @Override
self()288         Builder self() {
289             return this;
290         }
291 
292         /**
293          * Set the packet time i.e. recommended length of time in milliseconds
294          * represented by the media in each packet, see RFC 4566
295          *
296          * @param pTimeMillis packet time
297          * @return The same instance of the builder
298          */
setPtimeMillis(final byte pTimeMillis)299         public Builder setPtimeMillis(final byte pTimeMillis) {
300             this.pTimeMillis = pTimeMillis;
301             return this;
302         }
303 
304         /**
305          * Set the maximum amount of media that can be encapsulated in each packet
306          * represented in milliseconds, see RFC 4566
307          *
308          * @param maxPtimeMillis maximum packet time
309          * @return The same instance of the builder
310          */
setMaxPtimeMillis(final int maxPtimeMillis)311         public Builder setMaxPtimeMillis(final int maxPtimeMillis) {
312             this.maxPtimeMillis = maxPtimeMillis;
313             return this;
314         }
315 
316         /**
317          * Set whether discontinuous transmission (DTX) is enabled or not
318          *
319          * @param dtxEnabled {@code true} if DTX enabled
320          * @return The same instance of the builder
321          */
setDtxEnabled(final boolean dtxEnabled)322         public Builder setDtxEnabled(final boolean dtxEnabled) {
323             this.dtxEnabled = dtxEnabled;
324             return this;
325         }
326 
327         /**
328          * Set the negotiated audio codec
329          *
330          * @param codecType codec type
331          * @return The same instance of the builder
332          */
setCodecType(final @CodecType int codecType)333         public Builder setCodecType(final @CodecType int codecType) {
334             this.codecType = codecType;
335             return this;
336         }
337 
338         /**
339          * Set the dynamic Tx payload type number to be used to transmit DTMF RTP packets.
340          * The values is in the range from 96 to 127 chosen during the session establishment.
341          * The PT value of the RTP header of all DTMF packets shall be set with this value.
342          *
343          * @param dtmfTxPayloadTypeNumber Payload type number for the Tx DTMF packets
344          * @return The same instance of the builder
345          */
setTxDtmfPayloadTypeNumber(final byte dtmfTxPayloadTypeNumber)346         public Builder setTxDtmfPayloadTypeNumber(final byte dtmfTxPayloadTypeNumber) {
347             this.mDtmfTxPayloadTypeNumber = dtmfTxPayloadTypeNumber;
348             return this;
349         }
350 
351         /**
352          * Set the dynamic Rx payload type number to be used for DTMF received RTP packets.
353          * The values is in the range from 96 to 127 chosen during the session establishment.
354          * The PT value of the RTP header of all DTMF packets shall be set with this value.
355          *
356          * @param dtmfRxPayloadTypeNumber Payload type number for the Rx DTMF packets
357          * @return The same instance of the builder
358          */
setRxDtmfPayloadTypeNumber(final byte dtmfRxPayloadTypeNumber)359         public Builder setRxDtmfPayloadTypeNumber(final byte dtmfRxPayloadTypeNumber) {
360             this.mDtmfRxPayloadTypeNumber = dtmfRxPayloadTypeNumber;
361             return this;
362         }
363 
364         /**
365          * Set the DTMF sampling rate on this media stream
366          *
367          * @param dtmfSamplingRateKHz DTMF sampling rate
368          * @return The same instance of the builder
369          */
setDtmfSamplingRateKHz(final byte dtmfSamplingRateKHz)370         public Builder setDtmfSamplingRateKHz(final byte dtmfSamplingRateKHz) {
371             this.dtmfSamplingRateKHz = dtmfSamplingRateKHz;
372             return this;
373         }
374 
375         /**
376          * Set the AMR codec parameters, see {@link AmrParams}
377          *
378          * @param amrParams AMR parameters
379          * @return The same instance of the builder
380          */
setAmrParams(final AmrParams amrParams)381         public Builder setAmrParams(final AmrParams amrParams) {
382             this.amrParams = amrParams;
383             return this;
384         }
385 
386         /**
387          * Set the EVS codec parameters, see {@link EvsParams}
388          *
389          * @param evsParams EVS parameters.
390          * @return The same instance of the builder
391          */
setEvsParams(final EvsParams evsParams)392         public Builder setEvsParams(final EvsParams evsParams) {
393             this.evsParams = evsParams;
394             return this;
395         }
396 
397         /**
398          * Build the AudioConfig.
399          *
400          * @return the AudioConfig object.
401          */
build()402         public @NonNull AudioConfig build() {
403             // TODO validation
404             return new AudioConfig(this);
405         }
406     }
407 }
408 
409