1 /*
2  * Copyright (C) 2016 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.bluetooth;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.compat.annotation.UnsupportedAppUsage;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 
25 import java.lang.annotation.Retention;
26 import java.lang.annotation.RetentionPolicy;
27 import java.util.Objects;
28 
29 /**
30  * Represents the codec configuration for a Bluetooth A2DP source device.
31  *
32  * {@see BluetoothA2dp}
33  *
34  * {@hide}
35  */
36 public final class BluetoothCodecConfig implements Parcelable {
37     // Add an entry for each source codec here.
38     // NOTE: The values should be same as those listed in the following file:
39     //   hardware/libhardware/include/hardware/bt_av.h
40 
41     /** @hide */
42     @IntDef(prefix = "SOURCE_CODEC_TYPE_", value = {
43             SOURCE_CODEC_TYPE_SBC,
44             SOURCE_CODEC_TYPE_AAC,
45             SOURCE_CODEC_TYPE_APTX,
46             SOURCE_CODEC_TYPE_APTX_HD,
47             SOURCE_CODEC_TYPE_LDAC,
48             SOURCE_CODEC_TYPE_MAX,
49             SOURCE_CODEC_TYPE_INVALID
50     })
51     @Retention(RetentionPolicy.SOURCE)
52     public @interface SourceCodecType {}
53 
54     public static final int SOURCE_CODEC_TYPE_SBC = 0;
55 
56     public static final int SOURCE_CODEC_TYPE_AAC = 1;
57 
58     public static final int SOURCE_CODEC_TYPE_APTX = 2;
59 
60     public static final int SOURCE_CODEC_TYPE_APTX_HD = 3;
61 
62     public static final int SOURCE_CODEC_TYPE_LDAC = 4;
63 
64     public static final int SOURCE_CODEC_TYPE_MAX = 5;
65 
66 
67     public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000;
68 
69     /** @hide */
70     @IntDef(prefix = "CODEC_PRIORITY_", value = {
71             CODEC_PRIORITY_DISABLED,
72             CODEC_PRIORITY_DEFAULT,
73             CODEC_PRIORITY_HIGHEST
74     })
75     @Retention(RetentionPolicy.SOURCE)
76     public @interface CodecPriority {}
77 
78     public static final int CODEC_PRIORITY_DISABLED = -1;
79 
80     public static final int CODEC_PRIORITY_DEFAULT = 0;
81 
82     public static final int CODEC_PRIORITY_HIGHEST = 1000 * 1000;
83 
84 
85     /** @hide */
86     @IntDef(prefix = "SAMPLE_RATE_", value = {
87             SAMPLE_RATE_NONE,
88             SAMPLE_RATE_44100,
89             SAMPLE_RATE_48000,
90             SAMPLE_RATE_88200,
91             SAMPLE_RATE_96000,
92             SAMPLE_RATE_176400,
93             SAMPLE_RATE_192000
94     })
95     @Retention(RetentionPolicy.SOURCE)
96     public @interface SampleRate {}
97 
98     public static final int SAMPLE_RATE_NONE = 0;
99 
100     public static final int SAMPLE_RATE_44100 = 0x1 << 0;
101 
102     public static final int SAMPLE_RATE_48000 = 0x1 << 1;
103 
104     public static final int SAMPLE_RATE_88200 = 0x1 << 2;
105 
106     public static final int SAMPLE_RATE_96000 = 0x1 << 3;
107 
108     public static final int SAMPLE_RATE_176400 = 0x1 << 4;
109 
110     public static final int SAMPLE_RATE_192000 = 0x1 << 5;
111 
112 
113     /** @hide */
114     @IntDef(prefix = "BITS_PER_SAMPLE_", value = {
115             BITS_PER_SAMPLE_NONE,
116             BITS_PER_SAMPLE_16,
117             BITS_PER_SAMPLE_24,
118             BITS_PER_SAMPLE_32
119     })
120     @Retention(RetentionPolicy.SOURCE)
121     public @interface BitsPerSample {}
122 
123     public static final int BITS_PER_SAMPLE_NONE = 0;
124 
125     public static final int BITS_PER_SAMPLE_16 = 0x1 << 0;
126 
127     public static final int BITS_PER_SAMPLE_24 = 0x1 << 1;
128 
129     public static final int BITS_PER_SAMPLE_32 = 0x1 << 2;
130 
131 
132     /** @hide */
133     @IntDef(prefix = "CHANNEL_MODE_", value = {
134             CHANNEL_MODE_NONE,
135             CHANNEL_MODE_MONO,
136             CHANNEL_MODE_STEREO
137     })
138     @Retention(RetentionPolicy.SOURCE)
139     public @interface ChannelMode {}
140 
141     public static final int CHANNEL_MODE_NONE = 0;
142 
143     public static final int CHANNEL_MODE_MONO = 0x1 << 0;
144 
145     public static final int CHANNEL_MODE_STEREO = 0x1 << 1;
146 
147     private final @SourceCodecType int mCodecType;
148     private @CodecPriority int mCodecPriority;
149     private final @SampleRate int mSampleRate;
150     private final @BitsPerSample int mBitsPerSample;
151     private final @ChannelMode int mChannelMode;
152     private final long mCodecSpecific1;
153     private final long mCodecSpecific2;
154     private final long mCodecSpecific3;
155     private final long mCodecSpecific4;
156 
BluetoothCodecConfig(@ourceCodecType int codecType, @CodecPriority int codecPriority, @SampleRate int sampleRate, @BitsPerSample int bitsPerSample, @ChannelMode int channelMode, long codecSpecific1, long codecSpecific2, long codecSpecific3, long codecSpecific4)157     public BluetoothCodecConfig(@SourceCodecType int codecType, @CodecPriority int codecPriority,
158             @SampleRate int sampleRate, @BitsPerSample int bitsPerSample,
159             @ChannelMode int channelMode, long codecSpecific1,
160             long codecSpecific2, long codecSpecific3,
161             long codecSpecific4) {
162         mCodecType = codecType;
163         mCodecPriority = codecPriority;
164         mSampleRate = sampleRate;
165         mBitsPerSample = bitsPerSample;
166         mChannelMode = channelMode;
167         mCodecSpecific1 = codecSpecific1;
168         mCodecSpecific2 = codecSpecific2;
169         mCodecSpecific3 = codecSpecific3;
170         mCodecSpecific4 = codecSpecific4;
171     }
172 
BluetoothCodecConfig(@ourceCodecType int codecType)173     public BluetoothCodecConfig(@SourceCodecType int codecType) {
174         mCodecType = codecType;
175         mCodecPriority = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
176         mSampleRate = BluetoothCodecConfig.SAMPLE_RATE_NONE;
177         mBitsPerSample = BluetoothCodecConfig.BITS_PER_SAMPLE_NONE;
178         mChannelMode = BluetoothCodecConfig.CHANNEL_MODE_NONE;
179         mCodecSpecific1 = 0;
180         mCodecSpecific2 = 0;
181         mCodecSpecific3 = 0;
182         mCodecSpecific4 = 0;
183     }
184 
185     @Override
equals(Object o)186     public boolean equals(Object o) {
187         if (o instanceof BluetoothCodecConfig) {
188             BluetoothCodecConfig other = (BluetoothCodecConfig) o;
189             return (other.mCodecType == mCodecType
190                     && other.mCodecPriority == mCodecPriority
191                     && other.mSampleRate == mSampleRate
192                     && other.mBitsPerSample == mBitsPerSample
193                     && other.mChannelMode == mChannelMode
194                     && other.mCodecSpecific1 == mCodecSpecific1
195                     && other.mCodecSpecific2 == mCodecSpecific2
196                     && other.mCodecSpecific3 == mCodecSpecific3
197                     && other.mCodecSpecific4 == mCodecSpecific4);
198         }
199         return false;
200     }
201 
202     /**
203      * Returns a hash based on the config values
204      *
205      * @return a hash based on the config values
206      * @hide
207      */
208     @Override
hashCode()209     public int hashCode() {
210         return Objects.hash(mCodecType, mCodecPriority, mSampleRate,
211                 mBitsPerSample, mChannelMode, mCodecSpecific1,
212                 mCodecSpecific2, mCodecSpecific3, mCodecSpecific4);
213     }
214 
215     /**
216      * Checks whether the object contains valid codec configuration.
217      *
218      * @return true if the object contains valid codec configuration, otherwise false.
219      * @hide
220      */
isValid()221     public boolean isValid() {
222         return (mSampleRate != SAMPLE_RATE_NONE)
223                 && (mBitsPerSample != BITS_PER_SAMPLE_NONE)
224                 && (mChannelMode != CHANNEL_MODE_NONE);
225     }
226 
227     /**
228      * Adds capability string to an existing string.
229      *
230      * @param prevStr the previous string with the capabilities. Can be a null pointer.
231      * @param capStr the capability string to append to prevStr argument.
232      * @return the result string in the form "prevStr|capStr".
233      */
appendCapabilityToString(String prevStr, String capStr)234     private static String appendCapabilityToString(String prevStr,
235             String capStr) {
236         if (prevStr == null) {
237             return capStr;
238         }
239         return prevStr + "|" + capStr;
240     }
241 
242     @Override
toString()243     public String toString() {
244         String sampleRateStr = null;
245         if (mSampleRate == SAMPLE_RATE_NONE) {
246             sampleRateStr = appendCapabilityToString(sampleRateStr, "NONE");
247         }
248         if ((mSampleRate & SAMPLE_RATE_44100) != 0) {
249             sampleRateStr = appendCapabilityToString(sampleRateStr, "44100");
250         }
251         if ((mSampleRate & SAMPLE_RATE_48000) != 0) {
252             sampleRateStr = appendCapabilityToString(sampleRateStr, "48000");
253         }
254         if ((mSampleRate & SAMPLE_RATE_88200) != 0) {
255             sampleRateStr = appendCapabilityToString(sampleRateStr, "88200");
256         }
257         if ((mSampleRate & SAMPLE_RATE_96000) != 0) {
258             sampleRateStr = appendCapabilityToString(sampleRateStr, "96000");
259         }
260         if ((mSampleRate & SAMPLE_RATE_176400) != 0) {
261             sampleRateStr = appendCapabilityToString(sampleRateStr, "176400");
262         }
263         if ((mSampleRate & SAMPLE_RATE_192000) != 0) {
264             sampleRateStr = appendCapabilityToString(sampleRateStr, "192000");
265         }
266 
267         String bitsPerSampleStr = null;
268         if (mBitsPerSample == BITS_PER_SAMPLE_NONE) {
269             bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "NONE");
270         }
271         if ((mBitsPerSample & BITS_PER_SAMPLE_16) != 0) {
272             bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "16");
273         }
274         if ((mBitsPerSample & BITS_PER_SAMPLE_24) != 0) {
275             bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "24");
276         }
277         if ((mBitsPerSample & BITS_PER_SAMPLE_32) != 0) {
278             bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "32");
279         }
280 
281         String channelModeStr = null;
282         if (mChannelMode == CHANNEL_MODE_NONE) {
283             channelModeStr = appendCapabilityToString(channelModeStr, "NONE");
284         }
285         if ((mChannelMode & CHANNEL_MODE_MONO) != 0) {
286             channelModeStr = appendCapabilityToString(channelModeStr, "MONO");
287         }
288         if ((mChannelMode & CHANNEL_MODE_STEREO) != 0) {
289             channelModeStr = appendCapabilityToString(channelModeStr, "STEREO");
290         }
291 
292         return "{codecName:" + getCodecName()
293                 + ",mCodecType:" + mCodecType
294                 + ",mCodecPriority:" + mCodecPriority
295                 + ",mSampleRate:" + String.format("0x%x", mSampleRate)
296                 + "(" + sampleRateStr + ")"
297                 + ",mBitsPerSample:" + String.format("0x%x", mBitsPerSample)
298                 + "(" + bitsPerSampleStr + ")"
299                 + ",mChannelMode:" + String.format("0x%x", mChannelMode)
300                 + "(" + channelModeStr + ")"
301                 + ",mCodecSpecific1:" + mCodecSpecific1
302                 + ",mCodecSpecific2:" + mCodecSpecific2
303                 + ",mCodecSpecific3:" + mCodecSpecific3
304                 + ",mCodecSpecific4:" + mCodecSpecific4 + "}";
305     }
306 
307     /**
308      * Always returns 0
309      *
310      * @return 0
311      * @hide
312      */
313     @Override
describeContents()314     public int describeContents() {
315         return 0;
316     }
317 
318     public static final @android.annotation.NonNull Parcelable.Creator<BluetoothCodecConfig> CREATOR =
319             new Parcelable.Creator<BluetoothCodecConfig>() {
320                 public BluetoothCodecConfig createFromParcel(Parcel in) {
321                     final int codecType = in.readInt();
322                     final int codecPriority = in.readInt();
323                     final int sampleRate = in.readInt();
324                     final int bitsPerSample = in.readInt();
325                     final int channelMode = in.readInt();
326                     final long codecSpecific1 = in.readLong();
327                     final long codecSpecific2 = in.readLong();
328                     final long codecSpecific3 = in.readLong();
329                     final long codecSpecific4 = in.readLong();
330                     return new BluetoothCodecConfig(codecType, codecPriority,
331                             sampleRate, bitsPerSample,
332                             channelMode, codecSpecific1,
333                             codecSpecific2, codecSpecific3,
334                             codecSpecific4);
335                 }
336 
337                 public BluetoothCodecConfig[] newArray(int size) {
338                     return new BluetoothCodecConfig[size];
339                 }
340             };
341 
342     /**
343      * Flattens the object to a parcel
344      *
345      * @param out The Parcel in which the object should be written.
346      * @param flags Additional flags about how the object should be written.
347      *
348      * @hide
349      */
350     @Override
writeToParcel(Parcel out, int flags)351     public void writeToParcel(Parcel out, int flags) {
352         out.writeInt(mCodecType);
353         out.writeInt(mCodecPriority);
354         out.writeInt(mSampleRate);
355         out.writeInt(mBitsPerSample);
356         out.writeInt(mChannelMode);
357         out.writeLong(mCodecSpecific1);
358         out.writeLong(mCodecSpecific2);
359         out.writeLong(mCodecSpecific3);
360         out.writeLong(mCodecSpecific4);
361     }
362 
363     /**
364      * Gets the codec name.
365      *
366      * @return the codec name
367      */
getCodecName()368     public @NonNull String getCodecName() {
369         switch (mCodecType) {
370             case SOURCE_CODEC_TYPE_SBC:
371                 return "SBC";
372             case SOURCE_CODEC_TYPE_AAC:
373                 return "AAC";
374             case SOURCE_CODEC_TYPE_APTX:
375                 return "aptX";
376             case SOURCE_CODEC_TYPE_APTX_HD:
377                 return "aptX HD";
378             case SOURCE_CODEC_TYPE_LDAC:
379                 return "LDAC";
380             case SOURCE_CODEC_TYPE_INVALID:
381                 return "INVALID CODEC";
382             default:
383                 break;
384         }
385         return "UNKNOWN CODEC(" + mCodecType + ")";
386     }
387 
388     /**
389      * Gets the codec type.
390      * See {@link android.bluetooth.BluetoothCodecConfig#SOURCE_CODEC_TYPE_SBC}.
391      *
392      * @return the codec type
393      */
getCodecType()394     public @SourceCodecType int getCodecType() {
395         return mCodecType;
396     }
397 
398     /**
399      * Checks whether the codec is mandatory.
400      *
401      * @return true if the codec is mandatory, otherwise false.
402      */
isMandatoryCodec()403     public boolean isMandatoryCodec() {
404         return mCodecType == SOURCE_CODEC_TYPE_SBC;
405     }
406 
407     /**
408      * Gets the codec selection priority.
409      * The codec selection priority is relative to other codecs: larger value
410      * means higher priority. If 0, reset to default.
411      *
412      * @return the codec priority
413      */
getCodecPriority()414     public @CodecPriority int getCodecPriority() {
415         return mCodecPriority;
416     }
417 
418     /**
419      * Sets the codec selection priority.
420      * The codec selection priority is relative to other codecs: larger value
421      * means higher priority. If 0, reset to default.
422      *
423      * @param codecPriority the codec priority
424      * @hide
425      */
426     @UnsupportedAppUsage
setCodecPriority(@odecPriority int codecPriority)427     public void setCodecPriority(@CodecPriority int codecPriority) {
428         mCodecPriority = codecPriority;
429     }
430 
431     /**
432      * Gets the codec sample rate. The value can be a bitmask with all
433      * supported sample rates:
434      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_NONE} or
435      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_44100} or
436      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_48000} or
437      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_88200} or
438      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_96000} or
439      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_176400} or
440      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_192000}
441      *
442      * @return the codec sample rate
443      */
getSampleRate()444     public @SampleRate int getSampleRate() {
445         return mSampleRate;
446     }
447 
448     /**
449      * Gets the codec bits per sample. The value can be a bitmask with all
450      * bits per sample supported:
451      * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_NONE} or
452      * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_16} or
453      * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_24} or
454      * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_32}
455      *
456      * @return the codec bits per sample
457      */
getBitsPerSample()458     public @BitsPerSample int getBitsPerSample() {
459         return mBitsPerSample;
460     }
461 
462     /**
463      * Gets the codec channel mode. The value can be a bitmask with all
464      * supported channel modes:
465      * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_NONE} or
466      * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_MONO} or
467      * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_STEREO}
468      *
469      * @return the codec channel mode
470      * @hide
471      */
472     @UnsupportedAppUsage
getChannelMode()473     public @ChannelMode int getChannelMode() {
474         return mChannelMode;
475     }
476 
477     /**
478      * Gets a codec specific value1.
479      *
480      * @return a codec specific value1.
481      */
getCodecSpecific1()482     public long getCodecSpecific1() {
483         return mCodecSpecific1;
484     }
485 
486     /**
487      * Gets a codec specific value2.
488      *
489      * @return a codec specific value2
490      * @hide
491      */
492     @UnsupportedAppUsage
getCodecSpecific2()493     public long getCodecSpecific2() {
494         return mCodecSpecific2;
495     }
496 
497     /**
498      * Gets a codec specific value3.
499      *
500      * @return a codec specific value3
501      * @hide
502      */
503     @UnsupportedAppUsage
getCodecSpecific3()504     public long getCodecSpecific3() {
505         return mCodecSpecific3;
506     }
507 
508     /**
509      * Gets a codec specific value4.
510      *
511      * @return a codec specific value4
512      * @hide
513      */
514     @UnsupportedAppUsage
getCodecSpecific4()515     public long getCodecSpecific4() {
516         return mCodecSpecific4;
517     }
518 
519     /**
520      * Checks whether a value set presented by a bitmask has zero or single bit
521      *
522      * @param valueSet the value set presented by a bitmask
523      * @return true if the valueSet contains zero or single bit, otherwise false.
524      * @hide
525      */
hasSingleBit(int valueSet)526     private static boolean hasSingleBit(int valueSet) {
527         return (valueSet == 0 || (valueSet & (valueSet - 1)) == 0);
528     }
529 
530     /**
531      * Checks whether the object contains none or single sample rate.
532      *
533      * @return true if the object contains none or single sample rate, otherwise false.
534      * @hide
535      */
hasSingleSampleRate()536     public boolean hasSingleSampleRate() {
537         return hasSingleBit(mSampleRate);
538     }
539 
540     /**
541      * Checks whether the object contains none or single bits per sample.
542      *
543      * @return true if the object contains none or single bits per sample, otherwise false.
544      * @hide
545      */
hasSingleBitsPerSample()546     public boolean hasSingleBitsPerSample() {
547         return hasSingleBit(mBitsPerSample);
548     }
549 
550     /**
551      * Checks whether the object contains none or single channel mode.
552      *
553      * @return true if the object contains none or single channel mode, otherwise false.
554      * @hide
555      */
hasSingleChannelMode()556     public boolean hasSingleChannelMode() {
557         return hasSingleBit(mChannelMode);
558     }
559 
560     /**
561      * Checks whether the audio feeding parameters are same.
562      *
563      * @param other the codec config to compare against
564      * @return true if the audio feeding parameters are same, otherwise false
565      * @hide
566      */
sameAudioFeedingParameters(BluetoothCodecConfig other)567     public boolean sameAudioFeedingParameters(BluetoothCodecConfig other) {
568         return (other != null && other.mSampleRate == mSampleRate
569                 && other.mBitsPerSample == mBitsPerSample
570                 && other.mChannelMode == mChannelMode);
571     }
572 
573     /**
574      * Checks whether another codec config has the similar feeding parameters.
575      * Any parameters with NONE value will be considered to be a wildcard matching.
576      *
577      * @param other the codec config to compare against
578      * @return true if the audio feeding parameters are similar, otherwise false.
579      * @hide
580      */
similarCodecFeedingParameters(BluetoothCodecConfig other)581     public boolean similarCodecFeedingParameters(BluetoothCodecConfig other) {
582         if (other == null || mCodecType != other.mCodecType) {
583             return false;
584         }
585         int sampleRate = other.mSampleRate;
586         if (mSampleRate == BluetoothCodecConfig.SAMPLE_RATE_NONE
587                 || sampleRate == BluetoothCodecConfig.SAMPLE_RATE_NONE) {
588             sampleRate = mSampleRate;
589         }
590         int bitsPerSample = other.mBitsPerSample;
591         if (mBitsPerSample == BluetoothCodecConfig.BITS_PER_SAMPLE_NONE
592                 || bitsPerSample == BluetoothCodecConfig.BITS_PER_SAMPLE_NONE) {
593             bitsPerSample = mBitsPerSample;
594         }
595         int channelMode = other.mChannelMode;
596         if (mChannelMode == BluetoothCodecConfig.CHANNEL_MODE_NONE
597                 || channelMode == BluetoothCodecConfig.CHANNEL_MODE_NONE) {
598             channelMode = mChannelMode;
599         }
600         return sameAudioFeedingParameters(new BluetoothCodecConfig(
601                 mCodecType, /* priority */ 0, sampleRate, bitsPerSample, channelMode,
602                 /* specific1 */ 0, /* specific2 */ 0, /* specific3 */ 0,
603                 /* specific4 */ 0));
604     }
605 
606     /**
607      * Checks whether the codec specific parameters are the same.
608      *
609      * @param other the codec config to compare against
610      * @return true if the codec specific parameters are the same, otherwise false.
611      * @hide
612      */
sameCodecSpecificParameters(BluetoothCodecConfig other)613     public boolean sameCodecSpecificParameters(BluetoothCodecConfig other) {
614         if (other == null && mCodecType != other.mCodecType) {
615             return false;
616         }
617         // Currently we only care about the AAC VBR and LDAC Playback Quality at CodecSpecific1
618         switch (mCodecType) {
619             case SOURCE_CODEC_TYPE_AAC:
620             case SOURCE_CODEC_TYPE_LDAC:
621                 if (mCodecSpecific1 != other.mCodecSpecific1) {
622                     return false;
623                 }
624                 // fall through
625             default:
626                 return true;
627         }
628     }
629 }
630