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