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