1 /* 2 * Copyright (C) 2022 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.NonNull; 20 import android.annotation.Nullable; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 24 import java.util.Collections; 25 import java.util.List; 26 import java.util.Objects; 27 28 /** 29 * Represents the codec status (configuration and capability) for a Bluetooth Le Audio source 30 * device. 31 * 32 * @see BluetoothLeAudio 33 */ 34 public final class BluetoothLeAudioCodecStatus implements Parcelable { 35 /** 36 * Extra for the codec configuration intents of the individual profiles. 37 * 38 * <p>This extra represents the current codec status of the Le Audio profile. 39 */ 40 public static final String EXTRA_LE_AUDIO_CODEC_STATUS = 41 "android.bluetooth.extra.LE_AUDIO_CODEC_STATUS"; 42 43 private final @Nullable BluetoothLeAudioCodecConfig mInputCodecConfig; 44 private final @Nullable BluetoothLeAudioCodecConfig mOutputCodecConfig; 45 private final @Nullable List<BluetoothLeAudioCodecConfig> mInputCodecsLocalCapabilities; 46 private final @Nullable List<BluetoothLeAudioCodecConfig> mOutputCodecsLocalCapabilities; 47 private final @Nullable List<BluetoothLeAudioCodecConfig> mInputCodecsSelectableCapabilities; 48 private final @Nullable List<BluetoothLeAudioCodecConfig> mOutputCodecsSelectableCapabilities; 49 50 /** 51 * Represents the codec status for a Bluetooth LE Audio source device. 52 * 53 * @param inputCodecConfig the current input codec configuration. 54 * @param outputCodecConfig the current output codec configuration. 55 * @param inputCodecsLocalCapabilities the local input codecs capabilities. 56 * @param outputCodecsLocalCapabilities the local output codecs capabilities. 57 * @param inputCodecsSelectableCapabilities the selectable input codecs capabilities. 58 * @param outputCodecsSelectableCapabilities the selectable output codecs capabilities. 59 */ BluetoothLeAudioCodecStatus( @ullable BluetoothLeAudioCodecConfig inputCodecConfig, @Nullable BluetoothLeAudioCodecConfig outputCodecConfig, @NonNull List<BluetoothLeAudioCodecConfig> inputCodecsLocalCapabilities, @NonNull List<BluetoothLeAudioCodecConfig> outputCodecsLocalCapabilities, @NonNull List<BluetoothLeAudioCodecConfig> inputCodecsSelectableCapabilities, @NonNull List<BluetoothLeAudioCodecConfig> outputCodecsSelectableCapabilities)60 public BluetoothLeAudioCodecStatus( 61 @Nullable BluetoothLeAudioCodecConfig inputCodecConfig, 62 @Nullable BluetoothLeAudioCodecConfig outputCodecConfig, 63 @NonNull List<BluetoothLeAudioCodecConfig> inputCodecsLocalCapabilities, 64 @NonNull List<BluetoothLeAudioCodecConfig> outputCodecsLocalCapabilities, 65 @NonNull List<BluetoothLeAudioCodecConfig> inputCodecsSelectableCapabilities, 66 @NonNull List<BluetoothLeAudioCodecConfig> outputCodecsSelectableCapabilities) { 67 mInputCodecConfig = inputCodecConfig; 68 mOutputCodecConfig = outputCodecConfig; 69 mInputCodecsLocalCapabilities = inputCodecsLocalCapabilities; 70 mOutputCodecsLocalCapabilities = outputCodecsLocalCapabilities; 71 mInputCodecsSelectableCapabilities = inputCodecsSelectableCapabilities; 72 mOutputCodecsSelectableCapabilities = outputCodecsSelectableCapabilities; 73 } 74 BluetoothLeAudioCodecStatus(Parcel in)75 private BluetoothLeAudioCodecStatus(Parcel in) { 76 mInputCodecConfig = in.readTypedObject(BluetoothLeAudioCodecConfig.CREATOR); 77 mOutputCodecConfig = in.readTypedObject(BluetoothLeAudioCodecConfig.CREATOR); 78 mInputCodecsLocalCapabilities = 79 in.createTypedArrayList(BluetoothLeAudioCodecConfig.CREATOR); 80 mOutputCodecsLocalCapabilities = 81 in.createTypedArrayList(BluetoothLeAudioCodecConfig.CREATOR); 82 mInputCodecsSelectableCapabilities = 83 in.createTypedArrayList(BluetoothLeAudioCodecConfig.CREATOR); 84 mOutputCodecsSelectableCapabilities = 85 in.createTypedArrayList(BluetoothLeAudioCodecConfig.CREATOR); 86 } 87 88 @Override equals(@ullable Object o)89 public boolean equals(@Nullable Object o) { 90 if (o instanceof BluetoothLeAudioCodecStatus) { 91 BluetoothLeAudioCodecStatus other = (BluetoothLeAudioCodecStatus) o; 92 return (Objects.equals(other.mInputCodecConfig, mInputCodecConfig) 93 && Objects.equals(other.mOutputCodecConfig, mOutputCodecConfig) 94 && sameCapabilities( 95 other.mInputCodecsLocalCapabilities, mInputCodecsLocalCapabilities) 96 && sameCapabilities( 97 other.mOutputCodecsLocalCapabilities, mOutputCodecsLocalCapabilities) 98 && sameCapabilities( 99 other.mInputCodecsSelectableCapabilities, 100 mInputCodecsSelectableCapabilities) 101 && sameCapabilities( 102 other.mOutputCodecsSelectableCapabilities, 103 mOutputCodecsSelectableCapabilities)); 104 } 105 return false; 106 } 107 108 /** 109 * Checks whether two lists of capabilities contain same capabilities. The order of the 110 * capabilities in each list is ignored. 111 * 112 * @param c1 the first list of capabilities to compare 113 * @param c2 the second list of capabilities to compare 114 * @return {@code true} if both lists contain same capabilities 115 */ sameCapabilities( @ullable List<BluetoothLeAudioCodecConfig> c1, @Nullable List<BluetoothLeAudioCodecConfig> c2)116 private static boolean sameCapabilities( 117 @Nullable List<BluetoothLeAudioCodecConfig> c1, 118 @Nullable List<BluetoothLeAudioCodecConfig> c2) { 119 if (c1 == null) { 120 return (c2 == null); 121 } 122 if (c2 == null) { 123 return false; 124 } 125 if (c1.size() != c2.size()) { 126 return false; 127 } 128 return c1.containsAll(c2); 129 } 130 isCodecConfigSelectable( BluetoothLeAudioCodecConfig codecConfig, BluetoothLeAudioCodecConfig selectableConfig)131 private boolean isCodecConfigSelectable( 132 BluetoothLeAudioCodecConfig codecConfig, BluetoothLeAudioCodecConfig selectableConfig) { 133 if (codecConfig.getCodecType() != selectableConfig.getCodecType()) { 134 return false; 135 } 136 if ((codecConfig.getFrameDuration() != BluetoothLeAudioCodecConfig.FRAME_DURATION_NONE) 137 && ((codecConfig.getFrameDuration() & selectableConfig.getFrameDuration()) == 0)) { 138 return false; 139 } 140 if ((codecConfig.getChannelCount() != BluetoothLeAudioCodecConfig.CHANNEL_COUNT_NONE) 141 && ((codecConfig.getChannelCount() & selectableConfig.getChannelCount()) == 0)) { 142 return false; 143 } 144 if ((codecConfig.getSampleRate() != BluetoothLeAudioCodecConfig.SAMPLE_RATE_NONE) 145 && ((codecConfig.getSampleRate() & selectableConfig.getSampleRate()) == 0)) { 146 return false; 147 } 148 if ((codecConfig.getBitsPerSample() != BluetoothLeAudioCodecConfig.BITS_PER_SAMPLE_NONE) 149 && ((codecConfig.getBitsPerSample() & selectableConfig.getBitsPerSample()) == 0)) { 150 return false; 151 } 152 if ((codecConfig.getOctetsPerFrame() != 0) 153 && ((codecConfig.getOctetsPerFrame() < selectableConfig.getMinOctetsPerFrame()) 154 || (codecConfig.getOctetsPerFrame() 155 > selectableConfig.getMaxOctetsPerFrame()))) { 156 return false; 157 } 158 return true; 159 } 160 161 /** 162 * Checks whether the Input codec config matches the selectable capabilities. Any parameters of 163 * the codec config with NONE value will be considered a wildcard matching. 164 * 165 * @param codecConfig the codec config to compare against 166 * @return {@code true} if the codec config matches, {@code false} otherwise 167 */ isInputCodecConfigSelectable(@ullable BluetoothLeAudioCodecConfig codecConfig)168 public boolean isInputCodecConfigSelectable(@Nullable BluetoothLeAudioCodecConfig codecConfig) { 169 if (codecConfig == null) { 170 return false; 171 } 172 for (BluetoothLeAudioCodecConfig selectableConfig : mInputCodecsSelectableCapabilities) { 173 if (isCodecConfigSelectable(codecConfig, selectableConfig)) { 174 return true; 175 } 176 } 177 return false; 178 } 179 180 /** 181 * Checks whether the Output codec config matches the selectable capabilities. Any parameters of 182 * the codec config with NONE value will be considered a wildcard matching. 183 * 184 * @param codecConfig the codec config to compare against 185 * @return {@code true} if the codec config matches, {@code false} otherwise 186 */ isOutputCodecConfigSelectable( @ullable BluetoothLeAudioCodecConfig codecConfig)187 public boolean isOutputCodecConfigSelectable( 188 @Nullable BluetoothLeAudioCodecConfig codecConfig) { 189 if (codecConfig == null) { 190 return false; 191 } 192 for (BluetoothLeAudioCodecConfig selectableConfig : mOutputCodecsSelectableCapabilities) { 193 if (isCodecConfigSelectable(codecConfig, selectableConfig)) { 194 return true; 195 } 196 } 197 return false; 198 } 199 200 /** Returns a hash based on the codec config and local capabilities. */ 201 @Override hashCode()202 public int hashCode() { 203 return Objects.hash( 204 mInputCodecConfig, 205 mOutputCodecConfig, 206 mInputCodecsLocalCapabilities, 207 mOutputCodecsLocalCapabilities, 208 mInputCodecsSelectableCapabilities, 209 mOutputCodecsSelectableCapabilities); 210 } 211 212 /** 213 * Returns a {@link String} that describes each BluetoothLeAudioCodecStatus parameter current 214 * value. 215 */ 216 @Override toString()217 public String toString() { 218 return "{mInputCodecConfig:" 219 + mInputCodecConfig 220 + ",mOutputCodecConfig:" 221 + mOutputCodecConfig 222 + ",mInputCodecsLocalCapabilities:" 223 + mInputCodecsLocalCapabilities 224 + ",mOutputCodecsLocalCapabilities:" 225 + mOutputCodecsLocalCapabilities 226 + ",mInputCodecsSelectableCapabilities:" 227 + mInputCodecsSelectableCapabilities 228 + ",mOutputCodecsSelectableCapabilities:" 229 + mOutputCodecsSelectableCapabilities 230 + "}"; 231 } 232 233 /** 234 * @return 0 235 */ 236 @Override describeContents()237 public int describeContents() { 238 return 0; 239 } 240 241 /** {@link Parcelable.Creator} interface implementation. */ 242 public static final @android.annotation.NonNull Parcelable.Creator<BluetoothLeAudioCodecStatus> 243 CREATOR = 244 new Parcelable.Creator<BluetoothLeAudioCodecStatus>() { 245 public BluetoothLeAudioCodecStatus createFromParcel(Parcel in) { 246 return new BluetoothLeAudioCodecStatus(in); 247 } 248 249 public BluetoothLeAudioCodecStatus[] newArray(int size) { 250 return new BluetoothLeAudioCodecStatus[size]; 251 } 252 }; 253 254 /** 255 * Flattens the object to a parcel. 256 * 257 * @param out The Parcel in which the object should be written 258 * @param flags Additional flags about how the object should be written 259 */ 260 @Override writeToParcel(@onNull Parcel out, int flags)261 public void writeToParcel(@NonNull Parcel out, int flags) { 262 out.writeTypedObject(mInputCodecConfig, flags); 263 out.writeTypedObject(mOutputCodecConfig, flags); 264 out.writeTypedList(mInputCodecsLocalCapabilities); 265 out.writeTypedList(mOutputCodecsLocalCapabilities); 266 out.writeTypedList(mInputCodecsSelectableCapabilities); 267 out.writeTypedList(mOutputCodecsSelectableCapabilities); 268 } 269 270 /** 271 * Returns the current Input codec configuration. 272 * 273 * @return The current input codec config. 274 */ getInputCodecConfig()275 public @Nullable BluetoothLeAudioCodecConfig getInputCodecConfig() { 276 return mInputCodecConfig; 277 } 278 279 /** 280 * Returns the current Output codec configuration. 281 * 282 * @return The current output codec config. 283 */ getOutputCodecConfig()284 public @Nullable BluetoothLeAudioCodecConfig getOutputCodecConfig() { 285 return mOutputCodecConfig; 286 } 287 288 /** 289 * Returns the input codecs local capabilities. 290 * 291 * @return The list of codec config that supported by the local system. 292 */ getInputCodecLocalCapabilities()293 public @NonNull List<BluetoothLeAudioCodecConfig> getInputCodecLocalCapabilities() { 294 return (mInputCodecsLocalCapabilities == null) 295 ? Collections.emptyList() 296 : mInputCodecsLocalCapabilities; 297 } 298 299 /** 300 * Returns the output codecs local capabilities. 301 * 302 * @return The list of codec config that supported by the local system. 303 */ getOutputCodecLocalCapabilities()304 public @NonNull List<BluetoothLeAudioCodecConfig> getOutputCodecLocalCapabilities() { 305 return (mOutputCodecsLocalCapabilities == null) 306 ? Collections.emptyList() 307 : mOutputCodecsLocalCapabilities; 308 } 309 310 /** 311 * Returns the Input codecs selectable capabilities. 312 * 313 * @return The list of codec config that supported by both of the local system and remote 314 * devices. 315 */ getInputCodecSelectableCapabilities()316 public @NonNull List<BluetoothLeAudioCodecConfig> getInputCodecSelectableCapabilities() { 317 return (mInputCodecsSelectableCapabilities == null) 318 ? Collections.emptyList() 319 : mInputCodecsSelectableCapabilities; 320 } 321 322 /** 323 * Returns the Output codecs selectable capabilities. 324 * 325 * @return The list of codec config that supported by both of the local system and remote 326 * devices. 327 */ getOutputCodecSelectableCapabilities()328 public @NonNull List<BluetoothLeAudioCodecConfig> getOutputCodecSelectableCapabilities() { 329 return (mOutputCodecsSelectableCapabilities == null) 330 ? Collections.emptyList() 331 : mOutputCodecsSelectableCapabilities; 332 } 333 } 334