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.UnsupportedAppUsage;
20 import android.os.Parcel;
21 import android.os.Parcelable;
22 
23 import java.util.Objects;
24 
25 /**
26  * Represents the codec configuration for a Bluetooth A2DP source device.
27  *
28  * {@see BluetoothA2dp}
29  *
30  * {@hide}
31  */
32 public final class BluetoothCodecConfig implements Parcelable {
33     // Add an entry for each source codec here.
34     // NOTE: The values should be same as those listed in the following file:
35     //   hardware/libhardware/include/hardware/bt_av.h
36     @UnsupportedAppUsage
37     public static final int SOURCE_CODEC_TYPE_SBC = 0;
38     @UnsupportedAppUsage
39     public static final int SOURCE_CODEC_TYPE_AAC = 1;
40     @UnsupportedAppUsage
41     public static final int SOURCE_CODEC_TYPE_APTX = 2;
42     @UnsupportedAppUsage
43     public static final int SOURCE_CODEC_TYPE_APTX_HD = 3;
44     @UnsupportedAppUsage
45     public static final int SOURCE_CODEC_TYPE_LDAC = 4;
46     @UnsupportedAppUsage
47     public static final int SOURCE_CODEC_TYPE_MAX = 5;
48 
49     @UnsupportedAppUsage
50     public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000;
51 
52     @UnsupportedAppUsage
53     public static final int CODEC_PRIORITY_DISABLED = -1;
54     @UnsupportedAppUsage
55     public static final int CODEC_PRIORITY_DEFAULT = 0;
56     @UnsupportedAppUsage
57     public static final int CODEC_PRIORITY_HIGHEST = 1000 * 1000;
58 
59     @UnsupportedAppUsage
60     public static final int SAMPLE_RATE_NONE = 0;
61     @UnsupportedAppUsage
62     public static final int SAMPLE_RATE_44100 = 0x1 << 0;
63     @UnsupportedAppUsage
64     public static final int SAMPLE_RATE_48000 = 0x1 << 1;
65     @UnsupportedAppUsage
66     public static final int SAMPLE_RATE_88200 = 0x1 << 2;
67     @UnsupportedAppUsage
68     public static final int SAMPLE_RATE_96000 = 0x1 << 3;
69     @UnsupportedAppUsage
70     public static final int SAMPLE_RATE_176400 = 0x1 << 4;
71     @UnsupportedAppUsage
72     public static final int SAMPLE_RATE_192000 = 0x1 << 5;
73 
74     @UnsupportedAppUsage
75     public static final int BITS_PER_SAMPLE_NONE = 0;
76     @UnsupportedAppUsage
77     public static final int BITS_PER_SAMPLE_16 = 0x1 << 0;
78     @UnsupportedAppUsage
79     public static final int BITS_PER_SAMPLE_24 = 0x1 << 1;
80     @UnsupportedAppUsage
81     public static final int BITS_PER_SAMPLE_32 = 0x1 << 2;
82 
83     @UnsupportedAppUsage
84     public static final int CHANNEL_MODE_NONE = 0;
85     @UnsupportedAppUsage
86     public static final int CHANNEL_MODE_MONO = 0x1 << 0;
87     @UnsupportedAppUsage
88     public static final int CHANNEL_MODE_STEREO = 0x1 << 1;
89 
90     private final int mCodecType;
91     private int mCodecPriority;
92     private final int mSampleRate;
93     private final int mBitsPerSample;
94     private final int mChannelMode;
95     private final long mCodecSpecific1;
96     private final long mCodecSpecific2;
97     private final long mCodecSpecific3;
98     private final long mCodecSpecific4;
99 
100     @UnsupportedAppUsage
BluetoothCodecConfig(int codecType, int codecPriority, int sampleRate, int bitsPerSample, int channelMode, long codecSpecific1, long codecSpecific2, long codecSpecific3, long codecSpecific4)101     public BluetoothCodecConfig(int codecType, int codecPriority,
102             int sampleRate, int bitsPerSample,
103             int channelMode, long codecSpecific1,
104             long codecSpecific2, long codecSpecific3,
105             long codecSpecific4) {
106         mCodecType = codecType;
107         mCodecPriority = codecPriority;
108         mSampleRate = sampleRate;
109         mBitsPerSample = bitsPerSample;
110         mChannelMode = channelMode;
111         mCodecSpecific1 = codecSpecific1;
112         mCodecSpecific2 = codecSpecific2;
113         mCodecSpecific3 = codecSpecific3;
114         mCodecSpecific4 = codecSpecific4;
115     }
116 
117     @UnsupportedAppUsage
BluetoothCodecConfig(int codecType)118     public BluetoothCodecConfig(int codecType) {
119         mCodecType = codecType;
120         mCodecPriority = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
121         mSampleRate = BluetoothCodecConfig.SAMPLE_RATE_NONE;
122         mBitsPerSample = BluetoothCodecConfig.BITS_PER_SAMPLE_NONE;
123         mChannelMode = BluetoothCodecConfig.CHANNEL_MODE_NONE;
124         mCodecSpecific1 = 0;
125         mCodecSpecific2 = 0;
126         mCodecSpecific3 = 0;
127         mCodecSpecific4 = 0;
128     }
129 
130     @Override
equals(Object o)131     public boolean equals(Object o) {
132         if (o instanceof BluetoothCodecConfig) {
133             BluetoothCodecConfig other = (BluetoothCodecConfig) o;
134             return (other.mCodecType == mCodecType
135                     && other.mCodecPriority == mCodecPriority
136                     && other.mSampleRate == mSampleRate
137                     && other.mBitsPerSample == mBitsPerSample
138                     && other.mChannelMode == mChannelMode
139                     && other.mCodecSpecific1 == mCodecSpecific1
140                     && other.mCodecSpecific2 == mCodecSpecific2
141                     && other.mCodecSpecific3 == mCodecSpecific3
142                     && other.mCodecSpecific4 == mCodecSpecific4);
143         }
144         return false;
145     }
146 
147     @Override
hashCode()148     public int hashCode() {
149         return Objects.hash(mCodecType, mCodecPriority, mSampleRate,
150                 mBitsPerSample, mChannelMode, mCodecSpecific1,
151                 mCodecSpecific2, mCodecSpecific3, mCodecSpecific4);
152     }
153 
154     /**
155      * Checks whether the object contains valid codec configuration.
156      *
157      * @return true if the object contains valid codec configuration, otherwise false.
158      */
isValid()159     public boolean isValid() {
160         return (mSampleRate != SAMPLE_RATE_NONE)
161                 && (mBitsPerSample != BITS_PER_SAMPLE_NONE)
162                 && (mChannelMode != CHANNEL_MODE_NONE);
163     }
164 
165     /**
166      * Adds capability string to an existing string.
167      *
168      * @param prevStr the previous string with the capabilities. Can be a null pointer.
169      * @param capStr the capability string to append to prevStr argument.
170      * @return the result string in the form "prevStr|capStr".
171      */
appendCapabilityToString(String prevStr, String capStr)172     private static String appendCapabilityToString(String prevStr,
173             String capStr) {
174         if (prevStr == null) {
175             return capStr;
176         }
177         return prevStr + "|" + capStr;
178     }
179 
180     @Override
toString()181     public String toString() {
182         String sampleRateStr = null;
183         if (mSampleRate == SAMPLE_RATE_NONE) {
184             sampleRateStr = appendCapabilityToString(sampleRateStr, "NONE");
185         }
186         if ((mSampleRate & SAMPLE_RATE_44100) != 0) {
187             sampleRateStr = appendCapabilityToString(sampleRateStr, "44100");
188         }
189         if ((mSampleRate & SAMPLE_RATE_48000) != 0) {
190             sampleRateStr = appendCapabilityToString(sampleRateStr, "48000");
191         }
192         if ((mSampleRate & SAMPLE_RATE_88200) != 0) {
193             sampleRateStr = appendCapabilityToString(sampleRateStr, "88200");
194         }
195         if ((mSampleRate & SAMPLE_RATE_96000) != 0) {
196             sampleRateStr = appendCapabilityToString(sampleRateStr, "96000");
197         }
198         if ((mSampleRate & SAMPLE_RATE_176400) != 0) {
199             sampleRateStr = appendCapabilityToString(sampleRateStr, "176400");
200         }
201         if ((mSampleRate & SAMPLE_RATE_192000) != 0) {
202             sampleRateStr = appendCapabilityToString(sampleRateStr, "192000");
203         }
204 
205         String bitsPerSampleStr = null;
206         if (mBitsPerSample == BITS_PER_SAMPLE_NONE) {
207             bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "NONE");
208         }
209         if ((mBitsPerSample & BITS_PER_SAMPLE_16) != 0) {
210             bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "16");
211         }
212         if ((mBitsPerSample & BITS_PER_SAMPLE_24) != 0) {
213             bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "24");
214         }
215         if ((mBitsPerSample & BITS_PER_SAMPLE_32) != 0) {
216             bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "32");
217         }
218 
219         String channelModeStr = null;
220         if (mChannelMode == CHANNEL_MODE_NONE) {
221             channelModeStr = appendCapabilityToString(channelModeStr, "NONE");
222         }
223         if ((mChannelMode & CHANNEL_MODE_MONO) != 0) {
224             channelModeStr = appendCapabilityToString(channelModeStr, "MONO");
225         }
226         if ((mChannelMode & CHANNEL_MODE_STEREO) != 0) {
227             channelModeStr = appendCapabilityToString(channelModeStr, "STEREO");
228         }
229 
230         return "{codecName:" + getCodecName()
231                 + ",mCodecType:" + mCodecType
232                 + ",mCodecPriority:" + mCodecPriority
233                 + ",mSampleRate:" + String.format("0x%x", mSampleRate)
234                 + "(" + sampleRateStr + ")"
235                 + ",mBitsPerSample:" + String.format("0x%x", mBitsPerSample)
236                 + "(" + bitsPerSampleStr + ")"
237                 + ",mChannelMode:" + String.format("0x%x", mChannelMode)
238                 + "(" + channelModeStr + ")"
239                 + ",mCodecSpecific1:" + mCodecSpecific1
240                 + ",mCodecSpecific2:" + mCodecSpecific2
241                 + ",mCodecSpecific3:" + mCodecSpecific3
242                 + ",mCodecSpecific4:" + mCodecSpecific4 + "}";
243     }
244 
245     @Override
describeContents()246     public int describeContents() {
247         return 0;
248     }
249 
250     public static final @android.annotation.NonNull Parcelable.Creator<BluetoothCodecConfig> CREATOR =
251             new Parcelable.Creator<BluetoothCodecConfig>() {
252                 public BluetoothCodecConfig createFromParcel(Parcel in) {
253                     final int codecType = in.readInt();
254                     final int codecPriority = in.readInt();
255                     final int sampleRate = in.readInt();
256                     final int bitsPerSample = in.readInt();
257                     final int channelMode = in.readInt();
258                     final long codecSpecific1 = in.readLong();
259                     final long codecSpecific2 = in.readLong();
260                     final long codecSpecific3 = in.readLong();
261                     final long codecSpecific4 = in.readLong();
262                     return new BluetoothCodecConfig(codecType, codecPriority,
263                             sampleRate, bitsPerSample,
264                             channelMode, codecSpecific1,
265                             codecSpecific2, codecSpecific3,
266                             codecSpecific4);
267                 }
268 
269                 public BluetoothCodecConfig[] newArray(int size) {
270                     return new BluetoothCodecConfig[size];
271                 }
272             };
273 
274     @Override
writeToParcel(Parcel out, int flags)275     public void writeToParcel(Parcel out, int flags) {
276         out.writeInt(mCodecType);
277         out.writeInt(mCodecPriority);
278         out.writeInt(mSampleRate);
279         out.writeInt(mBitsPerSample);
280         out.writeInt(mChannelMode);
281         out.writeLong(mCodecSpecific1);
282         out.writeLong(mCodecSpecific2);
283         out.writeLong(mCodecSpecific3);
284         out.writeLong(mCodecSpecific4);
285     }
286 
287     /**
288      * Gets the codec name.
289      *
290      * @return the codec name
291      */
getCodecName()292     public String getCodecName() {
293         switch (mCodecType) {
294             case SOURCE_CODEC_TYPE_SBC:
295                 return "SBC";
296             case SOURCE_CODEC_TYPE_AAC:
297                 return "AAC";
298             case SOURCE_CODEC_TYPE_APTX:
299                 return "aptX";
300             case SOURCE_CODEC_TYPE_APTX_HD:
301                 return "aptX HD";
302             case SOURCE_CODEC_TYPE_LDAC:
303                 return "LDAC";
304             case SOURCE_CODEC_TYPE_INVALID:
305                 return "INVALID CODEC";
306             default:
307                 break;
308         }
309         return "UNKNOWN CODEC(" + mCodecType + ")";
310     }
311 
312     /**
313      * Gets the codec type.
314      * See {@link android.bluetooth.BluetoothCodecConfig#SOURCE_CODEC_TYPE_SBC}.
315      *
316      * @return the codec type
317      */
318     @UnsupportedAppUsage
getCodecType()319     public int getCodecType() {
320         return mCodecType;
321     }
322 
323     /**
324      * Checks whether the codec is mandatory.
325      *
326      * @return true if the codec is mandatory, otherwise false.
327      */
isMandatoryCodec()328     public boolean isMandatoryCodec() {
329         return mCodecType == SOURCE_CODEC_TYPE_SBC;
330     }
331 
332     /**
333      * Gets the codec selection priority.
334      * The codec selection priority is relative to other codecs: larger value
335      * means higher priority. If 0, reset to default.
336      *
337      * @return the codec priority
338      */
339     @UnsupportedAppUsage
getCodecPriority()340     public int getCodecPriority() {
341         return mCodecPriority;
342     }
343 
344     /**
345      * Sets the codec selection priority.
346      * The codec selection priority is relative to other codecs: larger value
347      * means higher priority. If 0, reset to default.
348      *
349      * @param codecPriority the codec priority
350      */
351     @UnsupportedAppUsage
setCodecPriority(int codecPriority)352     public void setCodecPriority(int codecPriority) {
353         mCodecPriority = codecPriority;
354     }
355 
356     /**
357      * Gets the codec sample rate. The value can be a bitmask with all
358      * supported sample rates:
359      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_NONE} or
360      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_44100} or
361      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_48000} or
362      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_88200} or
363      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_96000} or
364      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_176400} or
365      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_192000}
366      *
367      * @return the codec sample rate
368      */
369     @UnsupportedAppUsage
getSampleRate()370     public int getSampleRate() {
371         return mSampleRate;
372     }
373 
374     /**
375      * Gets the codec bits per sample. The value can be a bitmask with all
376      * bits per sample supported:
377      * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_NONE} or
378      * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_16} or
379      * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_24} or
380      * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_32}
381      *
382      * @return the codec bits per sample
383      */
384     @UnsupportedAppUsage
getBitsPerSample()385     public int getBitsPerSample() {
386         return mBitsPerSample;
387     }
388 
389     /**
390      * Gets the codec channel mode. The value can be a bitmask with all
391      * supported channel modes:
392      * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_NONE} or
393      * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_MONO} or
394      * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_STEREO}
395      *
396      * @return the codec channel mode
397      */
398     @UnsupportedAppUsage
getChannelMode()399     public int getChannelMode() {
400         return mChannelMode;
401     }
402 
403     /**
404      * Gets a codec specific value1.
405      *
406      * @return a codec specific value1.
407      */
408     @UnsupportedAppUsage
getCodecSpecific1()409     public long getCodecSpecific1() {
410         return mCodecSpecific1;
411     }
412 
413     /**
414      * Gets a codec specific value2.
415      *
416      * @return a codec specific value2
417      */
418     @UnsupportedAppUsage
getCodecSpecific2()419     public long getCodecSpecific2() {
420         return mCodecSpecific2;
421     }
422 
423     /**
424      * Gets a codec specific value3.
425      *
426      * @return a codec specific value3
427      */
428     @UnsupportedAppUsage
getCodecSpecific3()429     public long getCodecSpecific3() {
430         return mCodecSpecific3;
431     }
432 
433     /**
434      * Gets a codec specific value4.
435      *
436      * @return a codec specific value4
437      */
438     @UnsupportedAppUsage
getCodecSpecific4()439     public long getCodecSpecific4() {
440         return mCodecSpecific4;
441     }
442 
443     /**
444      * Checks whether the audio feeding parameters are same.
445      *
446      * @param other the codec config to compare against
447      * @return true if the audio feeding parameters are same, otherwise false
448      */
sameAudioFeedingParameters(BluetoothCodecConfig other)449     public boolean sameAudioFeedingParameters(BluetoothCodecConfig other) {
450         return (other != null && other.mSampleRate == mSampleRate
451                 && other.mBitsPerSample == mBitsPerSample
452                 && other.mChannelMode == mChannelMode);
453     }
454 }
455