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 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 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 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 */ 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 */ 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 354 public int getChannelMode() { 355 return mChannelMode; 356 } 357 358 /** 359 * Gets a codec specific value1. 360 * 361 * @return a codec specific value1. 362 */ 363 public long getCodecSpecific1() { 364 return mCodecSpecific1; 365 } 366 367 /** 368 * Gets a codec specific value2. 369 * 370 * @return a codec specific value2 371 */ 372 public long getCodecSpecific2() { 373 return mCodecSpecific2; 374 } 375 376 /** 377 * Gets a codec specific value3. 378 * 379 * @return a codec specific value3 380 */ 381 public long getCodecSpecific3() { 382 return mCodecSpecific3; 383 } 384 385 /** 386 * Gets a codec specific value4. 387 * 388 * @return a codec specific value4 389 */ 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 */ 400 public boolean sameAudioFeedingParameters(BluetoothCodecConfig other) { 401 return (other != null && other.mSampleRate == mSampleRate 402 && other.mBitsPerSample == mBitsPerSample 403 && other.mChannelMode == mChannelMode); 404 } 405 } 406