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