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,
119      * otherwise false.
120      */
isValid()121     public boolean isValid() {
122         return (mSampleRate != SAMPLE_RATE_NONE) &&
123             (mBitsPerSample != BITS_PER_SAMPLE_NONE) &&
124             (mChannelMode != CHANNEL_MODE_NONE);
125     }
126 
127     /**
128      * Adds capability string to an existing string.
129      *
130      * @param prevStr the previous string with the capabilities. Can be
131      * a null pointer.
132      * @param capStr the capability string to append to prevStr argument.
133      * @return the result string in the form "prevStr|capStr".
134      */
appendCapabilityToString(String prevStr, String capStr)135     private static String appendCapabilityToString(String prevStr,
136                                                    String capStr) {
137         if (prevStr == null) {
138             return capStr;
139         }
140         return prevStr + "|" + capStr;
141     }
142 
143     @Override
toString()144     public String toString() {
145         String sampleRateStr = null;
146         if (mSampleRate == SAMPLE_RATE_NONE) {
147             sampleRateStr = appendCapabilityToString(sampleRateStr, "NONE");
148         }
149         if ((mSampleRate & SAMPLE_RATE_44100) != 0) {
150             sampleRateStr = appendCapabilityToString(sampleRateStr, "44100");
151         }
152         if ((mSampleRate & SAMPLE_RATE_48000) != 0) {
153             sampleRateStr = appendCapabilityToString(sampleRateStr, "48000");
154         }
155         if ((mSampleRate & SAMPLE_RATE_88200) != 0) {
156             sampleRateStr = appendCapabilityToString(sampleRateStr, "88200");
157         }
158         if ((mSampleRate & SAMPLE_RATE_96000) != 0) {
159             sampleRateStr = appendCapabilityToString(sampleRateStr, "96000");
160         }
161         if ((mSampleRate & SAMPLE_RATE_176400) != 0) {
162             sampleRateStr = appendCapabilityToString(sampleRateStr, "176400");
163         }
164         if ((mSampleRate & SAMPLE_RATE_192000) != 0) {
165             sampleRateStr = appendCapabilityToString(sampleRateStr, "192000");
166         }
167 
168         String bitsPerSampleStr = null;
169         if (mBitsPerSample == BITS_PER_SAMPLE_NONE) {
170             bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "NONE");
171         }
172         if ((mBitsPerSample & BITS_PER_SAMPLE_16) != 0) {
173             bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "16");
174         }
175         if ((mBitsPerSample & BITS_PER_SAMPLE_24) != 0) {
176             bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "24");
177         }
178         if ((mBitsPerSample & BITS_PER_SAMPLE_32) != 0) {
179             bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "32");
180         }
181 
182         String channelModeStr = null;
183         if (mChannelMode == CHANNEL_MODE_NONE) {
184             channelModeStr = appendCapabilityToString(channelModeStr, "NONE");
185         }
186         if ((mChannelMode & CHANNEL_MODE_MONO) != 0) {
187             channelModeStr = appendCapabilityToString(channelModeStr, "MONO");
188         }
189         if ((mChannelMode & CHANNEL_MODE_STEREO) != 0) {
190             channelModeStr = appendCapabilityToString(channelModeStr, "STEREO");
191         }
192 
193         return "{codecName:" + getCodecName() +
194             ",mCodecType:" + mCodecType +
195             ",mCodecPriority:" + mCodecPriority +
196             ",mSampleRate:" + String.format("0x%x", mSampleRate) +
197             "(" + sampleRateStr + ")" +
198             ",mBitsPerSample:" + String.format("0x%x", mBitsPerSample) +
199             "(" + bitsPerSampleStr + ")" +
200             ",mChannelMode:" + String.format("0x%x", mChannelMode) +
201             "(" + channelModeStr + ")" +
202             ",mCodecSpecific1:" + mCodecSpecific1 +
203             ",mCodecSpecific2:" + mCodecSpecific2 +
204             ",mCodecSpecific3:" + mCodecSpecific3 +
205             ",mCodecSpecific4:" + mCodecSpecific4 + "}";
206     }
207 
describeContents()208     public int describeContents() {
209         return 0;
210     }
211 
212     public static final Parcelable.Creator<BluetoothCodecConfig> CREATOR =
213             new Parcelable.Creator<BluetoothCodecConfig>() {
214         public BluetoothCodecConfig createFromParcel(Parcel in) {
215             final int codecType = in.readInt();
216             final int codecPriority = in.readInt();
217             final int sampleRate = in.readInt();
218             final int bitsPerSample = in.readInt();
219             final int channelMode = in.readInt();
220             final long codecSpecific1 = in.readLong();
221             final long codecSpecific2 = in.readLong();
222             final long codecSpecific3 = in.readLong();
223             final long codecSpecific4 = in.readLong();
224             return new BluetoothCodecConfig(codecType, codecPriority,
225                                             sampleRate, bitsPerSample,
226                                             channelMode, codecSpecific1,
227                                             codecSpecific2, codecSpecific3,
228                                             codecSpecific4);
229         }
230         public BluetoothCodecConfig[] newArray(int size) {
231             return new BluetoothCodecConfig[size];
232         }
233     };
234 
writeToParcel(Parcel out, int flags)235     public void writeToParcel(Parcel out, int flags) {
236         out.writeInt(mCodecType);
237         out.writeInt(mCodecPriority);
238         out.writeInt(mSampleRate);
239         out.writeInt(mBitsPerSample);
240         out.writeInt(mChannelMode);
241         out.writeLong(mCodecSpecific1);
242         out.writeLong(mCodecSpecific2);
243         out.writeLong(mCodecSpecific3);
244         out.writeLong(mCodecSpecific4);
245     }
246 
247     /**
248      * Gets the codec name.
249      *
250      * @return the codec name
251      */
getCodecName()252     public String getCodecName() {
253         switch (mCodecType) {
254         case SOURCE_CODEC_TYPE_SBC:
255             return "SBC";
256         case SOURCE_CODEC_TYPE_AAC:
257             return "AAC";
258         case SOURCE_CODEC_TYPE_APTX:
259             return "aptX";
260         case SOURCE_CODEC_TYPE_APTX_HD:
261             return "aptX HD";
262         case SOURCE_CODEC_TYPE_LDAC:
263             return "LDAC";
264         case SOURCE_CODEC_TYPE_INVALID:
265             return "INVALID CODEC";
266         default:
267             break;
268         }
269         return "UNKNOWN CODEC(" + mCodecType + ")";
270     }
271 
272     /**
273      * Gets the codec type.
274      * See {@link android.bluetooth.BluetoothCodecConfig#SOURCE_CODEC_TYPE_SBC}.
275      *
276      * @return the codec type
277      */
getCodecType()278     public int getCodecType() {
279         return mCodecType;
280     }
281 
282     /**
283      * Checks whether the codec is mandatory.
284      *
285      * @return true if the codec is mandatory, otherwise false.
286      */
isMandatoryCodec()287     public boolean isMandatoryCodec() {
288         return mCodecType == SOURCE_CODEC_TYPE_SBC;
289     }
290 
291     /**
292      * Gets the codec selection priority.
293      * The codec selection priority is relative to other codecs: larger value
294      * means higher priority. If 0, reset to default.
295      *
296      * @return the codec priority
297      */
getCodecPriority()298     public int getCodecPriority() {
299         return mCodecPriority;
300     }
301 
302     /**
303      * Sets the codec selection priority.
304      * The codec selection priority is relative to other codecs: larger value
305      * means higher priority. If 0, reset to default.
306      *
307      * @param codecPriority the codec priority
308      */
setCodecPriority(int codecPriority)309     public void setCodecPriority(int codecPriority) {
310         mCodecPriority = codecPriority;
311     }
312 
313     /**
314      * Gets the codec sample rate. The value can be a bitmask with all
315      * supported sample rates:
316      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_NONE} or
317      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_44100} or
318      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_48000} or
319      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_88200} or
320      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_96000} or
321      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_176400} or
322      * {@link android.bluetooth.BluetoothCodecConfig#SAMPLE_RATE_192000}
323      *
324      * @return the codec sample rate
325      */
getSampleRate()326     public int getSampleRate() {
327         return mSampleRate;
328     }
329 
330     /**
331      * Gets the codec bits per sample. The value can be a bitmask with all
332      * bits per sample supported:
333      * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_NONE} or
334      * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_16} or
335      * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_24} or
336      * {@link android.bluetooth.BluetoothCodecConfig#BITS_PER_SAMPLE_32}
337      *
338      * @return the codec bits per sample
339      */
getBitsPerSample()340     public int getBitsPerSample() {
341         return mBitsPerSample;
342     }
343 
344     /**
345      * Gets the codec channel mode. The value can be a bitmask with all
346      * supported channel modes:
347      * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_NONE} or
348      * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_MONO} or
349      * {@link android.bluetooth.BluetoothCodecConfig#CHANNEL_MODE_STEREO}
350      *
351      * @return the codec channel mode
352      */
getChannelMode()353     public int getChannelMode() {
354         return mChannelMode;
355     }
356 
357     /**
358      * Gets a codec specific value1.
359      *
360      * @return a codec specific value1.
361      */
getCodecSpecific1()362     public long getCodecSpecific1() {
363         return mCodecSpecific1;
364     }
365 
366     /**
367      * Gets a codec specific value2.
368      *
369      * @return a codec specific value2
370      */
getCodecSpecific2()371     public long getCodecSpecific2() {
372         return mCodecSpecific2;
373     }
374 
375     /**
376      * Gets a codec specific value3.
377      *
378      * @return a codec specific value3
379      */
getCodecSpecific3()380     public long getCodecSpecific3() {
381         return mCodecSpecific3;
382     }
383 
384     /**
385      * Gets a codec specific value4.
386      *
387      * @return a codec specific value4
388      */
getCodecSpecific4()389     public long getCodecSpecific4() {
390         return mCodecSpecific4;
391     }
392 
393     /**
394      * Checks whether the audio feeding parameters are same.
395      *
396      * @param other the codec config to compare against
397      * @return true if the audio feeding parameters are same, otherwise false
398      */
sameAudioFeedingParameters(BluetoothCodecConfig other)399     public boolean sameAudioFeedingParameters(BluetoothCodecConfig other) {
400         return (other != null && other.mSampleRate == mSampleRate &&
401                 other.mBitsPerSample == mBitsPerSample &&
402                 other.mChannelMode == mChannelMode);
403     }
404 }
405