| /* |
| * Copyright (C) 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.bluetooth; |
| |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Objects; |
| |
| /** |
| * Represents the codec status (configuration and capability) for a Bluetooth |
| * Le Audio source device. |
| * |
| * {@see BluetoothLeAudio} |
| */ |
| public final class BluetoothLeAudioCodecStatus implements Parcelable { |
| /** |
| * Extra for the codec configuration intents of the individual profiles. |
| * |
| * This extra represents the current codec status of the Le Audio |
| * profile. |
| */ |
| public static final String EXTRA_LE_AUDIO_CODEC_STATUS = |
| "android.bluetooth.extra.LE_AUDIO_CODEC_STATUS"; |
| |
| private final @Nullable BluetoothLeAudioCodecConfig mInputCodecConfig; |
| private final @Nullable BluetoothLeAudioCodecConfig mOutputCodecConfig; |
| private final @Nullable List<BluetoothLeAudioCodecConfig> mInputCodecsLocalCapabilities; |
| private final @Nullable List<BluetoothLeAudioCodecConfig> mOutputCodecsLocalCapabilities; |
| private final @Nullable List<BluetoothLeAudioCodecConfig> mInputCodecsSelectableCapabilities; |
| private final @Nullable List<BluetoothLeAudioCodecConfig> mOutputCodecsSelectableCapabilities; |
| |
| /** |
| * Represents the codec status for a Bluetooth LE Audio source device. |
| * |
| * @param inputCodecConfig the current input code configutration. |
| * @param outputCodecConfig the current output code configutration. |
| * @param inputCodecsLocalCapabilities the local input codecs capabilities. |
| * @param outputCodecsLocalCapabilities the local output codecs capabilities. |
| * @param inputCodecsSelectableCapabilities the selectable input codecs capabilities. |
| * @param outputCodecsSelectableCapabilities the selectable output codecs capabilities. |
| */ |
| public BluetoothLeAudioCodecStatus(@Nullable BluetoothLeAudioCodecConfig inputCodecConfig, |
| @Nullable BluetoothLeAudioCodecConfig outputCodecConfig, |
| @NonNull List<BluetoothLeAudioCodecConfig> inputCodecsLocalCapabilities, |
| @NonNull List<BluetoothLeAudioCodecConfig> outputCodecsLocalCapabilities, |
| @NonNull List<BluetoothLeAudioCodecConfig> inputCodecsSelectableCapabilities, |
| @NonNull List<BluetoothLeAudioCodecConfig> outputCodecsSelectableCapabilities) { |
| mInputCodecConfig = inputCodecConfig; |
| mOutputCodecConfig = outputCodecConfig; |
| mInputCodecsLocalCapabilities = inputCodecsLocalCapabilities; |
| mOutputCodecsLocalCapabilities = outputCodecsLocalCapabilities; |
| mInputCodecsSelectableCapabilities = inputCodecsSelectableCapabilities; |
| mOutputCodecsSelectableCapabilities = outputCodecsSelectableCapabilities; |
| } |
| |
| private BluetoothLeAudioCodecStatus(Parcel in) { |
| mInputCodecConfig = in.readTypedObject(BluetoothLeAudioCodecConfig.CREATOR); |
| mOutputCodecConfig = in.readTypedObject(BluetoothLeAudioCodecConfig.CREATOR); |
| mInputCodecsLocalCapabilities = |
| in.createTypedArrayList(BluetoothLeAudioCodecConfig.CREATOR); |
| mOutputCodecsLocalCapabilities = |
| in.createTypedArrayList(BluetoothLeAudioCodecConfig.CREATOR); |
| mInputCodecsSelectableCapabilities = |
| in.createTypedArrayList(BluetoothLeAudioCodecConfig.CREATOR); |
| mOutputCodecsSelectableCapabilities = |
| in.createTypedArrayList(BluetoothLeAudioCodecConfig.CREATOR); |
| } |
| |
| @Override |
| public boolean equals(@Nullable Object o) { |
| if (o instanceof BluetoothLeAudioCodecStatus) { |
| BluetoothLeAudioCodecStatus other = (BluetoothLeAudioCodecStatus) o; |
| return (Objects.equals(other.mInputCodecConfig, mInputCodecConfig) |
| && Objects.equals(other.mOutputCodecConfig, mOutputCodecConfig) |
| && sameCapabilities(other.mInputCodecsLocalCapabilities, |
| mInputCodecsLocalCapabilities) |
| && sameCapabilities(other.mOutputCodecsLocalCapabilities, |
| mOutputCodecsLocalCapabilities) |
| && sameCapabilities(other.mInputCodecsSelectableCapabilities, |
| mInputCodecsSelectableCapabilities) |
| && sameCapabilities(other.mOutputCodecsSelectableCapabilities, |
| mOutputCodecsSelectableCapabilities)); |
| } |
| return false; |
| } |
| |
| /** |
| * Checks whether two lists of capabilities contain same capabilities. |
| * The order of the capabilities in each list is ignored. |
| * |
| * @param c1 the first list of capabilities to compare |
| * @param c2 the second list of capabilities to compare |
| * @return {@code true} if both lists contain same capabilities |
| */ |
| private static boolean sameCapabilities(@Nullable List<BluetoothLeAudioCodecConfig> c1, |
| @Nullable List<BluetoothLeAudioCodecConfig> c2) { |
| if (c1 == null) { |
| return (c2 == null); |
| } |
| if (c2 == null) { |
| return false; |
| } |
| if (c1.size() != c2.size()) { |
| return false; |
| } |
| return c1.containsAll(c2); |
| } |
| |
| private boolean isCodecConfigSelectable(BluetoothLeAudioCodecConfig codecConfig, |
| BluetoothLeAudioCodecConfig selectableConfig) { |
| if (codecConfig.getCodecType() != selectableConfig.getCodecType()) { |
| return false; |
| } |
| if ((codecConfig.getFrameDuration() != BluetoothLeAudioCodecConfig.FRAME_DURATION_NONE) |
| && ((codecConfig.getFrameDuration() & selectableConfig.getFrameDuration()) == 0)) { |
| return false; |
| } |
| if ((codecConfig.getChannelCount() != BluetoothLeAudioCodecConfig.CHANNEL_COUNT_NONE) |
| && ((codecConfig.getChannelCount() & selectableConfig.getChannelCount()) == 0)) { |
| return false; |
| } |
| if ((codecConfig.getSampleRate() != BluetoothLeAudioCodecConfig.SAMPLE_RATE_NONE) |
| && ((codecConfig.getSampleRate() & selectableConfig.getSampleRate()) == 0)) { |
| return false; |
| } |
| if ((codecConfig.getBitsPerSample() != BluetoothLeAudioCodecConfig.BITS_PER_SAMPLE_NONE) |
| && ((codecConfig.getBitsPerSample() & selectableConfig.getBitsPerSample()) == 0)) { |
| return false; |
| } |
| if ((codecConfig.getOctetsPerFrame() != 0) |
| && ((codecConfig.getOctetsPerFrame() < selectableConfig.getMinOctetsPerFrame()) |
| || (codecConfig.getOctetsPerFrame() > selectableConfig.getMaxOctetsPerFrame()))) { |
| return false; |
| } |
| return true; |
| } |
| /** |
| * Checks whether the Input codec config matches the selectable capabilities. |
| * Any parameters of the codec config with NONE value will be considered a wildcard matching. |
| * |
| * @param codecConfig the codec config to compare against |
| * @return {@code true} if the codec config matches, {@code false} otherwise |
| */ |
| public boolean isInputCodecConfigSelectable(@Nullable BluetoothLeAudioCodecConfig codecConfig) { |
| if (codecConfig == null) { |
| return false; |
| } |
| for (BluetoothLeAudioCodecConfig selectableConfig : mInputCodecsSelectableCapabilities) { |
| if (isCodecConfigSelectable(codecConfig, selectableConfig)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Checks whether the Output codec config matches the selectable capabilities. |
| * Any parameters of the codec config with NONE value will be considered a wildcard matching. |
| * |
| * @param codecConfig the codec config to compare against |
| * @return {@code true} if the codec config matches, {@code false} otherwise |
| */ |
| public boolean isOutputCodecConfigSelectable( |
| @Nullable BluetoothLeAudioCodecConfig codecConfig) { |
| if (codecConfig == null) { |
| return false; |
| } |
| for (BluetoothLeAudioCodecConfig selectableConfig : mOutputCodecsSelectableCapabilities) { |
| if (isCodecConfigSelectable(codecConfig, selectableConfig)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Returns a hash based on the codec config and local capabilities. |
| */ |
| @Override |
| public int hashCode() { |
| return Objects.hash(mInputCodecConfig, mOutputCodecConfig, |
| mInputCodecsLocalCapabilities, mOutputCodecsLocalCapabilities, |
| mInputCodecsSelectableCapabilities, mOutputCodecsSelectableCapabilities); |
| } |
| |
| /** |
| * Returns a {@link String} that describes each BluetoothLeAudioCodecStatus parameter |
| * current value. |
| */ |
| @Override |
| public String toString() { |
| return "{mInputCodecConfig:" + mInputCodecConfig |
| + ",mOutputCodecConfig:" + mOutputCodecConfig |
| + ",mInputCodecsLocalCapabilities:" + mInputCodecsLocalCapabilities |
| + ",mOutputCodecsLocalCapabilities:" + mOutputCodecsLocalCapabilities |
| + ",mInputCodecsSelectableCapabilities:" + mInputCodecsSelectableCapabilities |
| + ",mOutputCodecsSelectableCapabilities:" + mOutputCodecsSelectableCapabilities |
| + "}"; |
| } |
| |
| /** |
| * @return 0 |
| */ |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| /** |
| * {@link Parcelable.Creator} interface implementation. |
| */ |
| public static final @android.annotation.NonNull |
| Parcelable.Creator<BluetoothLeAudioCodecStatus> CREATOR = |
| new Parcelable.Creator<BluetoothLeAudioCodecStatus>() { |
| public BluetoothLeAudioCodecStatus createFromParcel(Parcel in) { |
| return new BluetoothLeAudioCodecStatus(in); |
| } |
| |
| public BluetoothLeAudioCodecStatus[] newArray(int size) { |
| return new BluetoothLeAudioCodecStatus[size]; |
| } |
| }; |
| |
| /** |
| * Flattens the object to a parcel. |
| * |
| * @param out The Parcel in which the object should be written |
| * @param flags Additional flags about how the object should be written |
| */ |
| @Override |
| public void writeToParcel(@NonNull Parcel out, int flags) { |
| out.writeTypedObject(mInputCodecConfig, flags); |
| out.writeTypedObject(mOutputCodecConfig, flags); |
| out.writeTypedList(mInputCodecsLocalCapabilities); |
| out.writeTypedList(mOutputCodecsLocalCapabilities); |
| out.writeTypedList(mInputCodecsSelectableCapabilities); |
| out.writeTypedList(mOutputCodecsSelectableCapabilities); |
| } |
| |
| /** |
| * Returns the current Input codec configuration. |
| * |
| * @return The current input codec config. |
| */ |
| public @Nullable BluetoothLeAudioCodecConfig getInputCodecConfig() { |
| return mInputCodecConfig; |
| } |
| |
| /** |
| * Returns the current Output codec configuration. |
| * |
| * @return The current output codec config. |
| */ |
| public @Nullable BluetoothLeAudioCodecConfig getOutputCodecConfig() { |
| return mOutputCodecConfig; |
| } |
| |
| /** |
| * Returns the input codecs local capabilities. |
| * |
| * @return The list of codec config that supported by the local system. |
| */ |
| public @NonNull List<BluetoothLeAudioCodecConfig> getInputCodecLocalCapabilities() { |
| return (mInputCodecsLocalCapabilities == null) |
| ? Collections.emptyList() : mInputCodecsLocalCapabilities; |
| } |
| |
| /** |
| * Returns the output codecs local capabilities. |
| * |
| * @return The list of codec config that supported by the local system. |
| */ |
| public @NonNull List<BluetoothLeAudioCodecConfig> getOutputCodecLocalCapabilities() { |
| return (mOutputCodecsLocalCapabilities == null) |
| ? Collections.emptyList() : mOutputCodecsLocalCapabilities; |
| } |
| |
| /** |
| * Returns the Input codecs selectable capabilities. |
| * |
| * @return The list of codec config that supported by both of the local system and |
| * remote devices. |
| */ |
| public @NonNull List<BluetoothLeAudioCodecConfig> getInputCodecSelectableCapabilities() { |
| return (mInputCodecsSelectableCapabilities == null) |
| ? Collections.emptyList() : mInputCodecsSelectableCapabilities; |
| } |
| |
| /** |
| * Returns the Output codecs selectable capabilities. |
| * |
| * @return The list of codec config that supported by both of the local system and |
| * remote devices. |
| */ |
| public @NonNull List<BluetoothLeAudioCodecConfig> getOutputCodecSelectableCapabilities() { |
| return (mOutputCodecsSelectableCapabilities == null) |
| ? Collections.emptyList() : mOutputCodecsSelectableCapabilities; |
| } |
| } |