1 /* 2 * Copyright 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.annotation.SystemApi; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 25 import java.util.Objects; 26 27 /** 28 * This class contains the Broadcast Isochronous Channel level information as defined in the BASE 29 * structure of the Basic Audio Profile. 30 * 31 * @hide 32 */ 33 @SystemApi 34 public final class BluetoothLeBroadcastChannel implements Parcelable { 35 private static final int UNKNOWN_VALUE_PLACEHOLDER = -1; 36 37 private final boolean mIsSelected; 38 private final int mChannelIndex; 39 private final BluetoothLeAudioCodecConfigMetadata mCodecMetadata; 40 BluetoothLeBroadcastChannel(boolean isSelected, int channelIndex, BluetoothLeAudioCodecConfigMetadata codecMetadata)41 private BluetoothLeBroadcastChannel(boolean isSelected, int channelIndex, 42 BluetoothLeAudioCodecConfigMetadata codecMetadata) { 43 mIsSelected = isSelected; 44 mChannelIndex = channelIndex; 45 mCodecMetadata = codecMetadata; 46 } 47 48 @Override equals(@ullable Object o)49 public boolean equals(@Nullable Object o) { 50 if (!(o instanceof BluetoothLeBroadcastChannel)) { 51 return false; 52 } 53 final BluetoothLeBroadcastChannel other = (BluetoothLeBroadcastChannel) o; 54 return mIsSelected == other.isSelected() 55 && mChannelIndex == other.getChannelIndex() 56 && mCodecMetadata.equals(other.getCodecMetadata()); 57 } 58 59 @Override hashCode()60 public int hashCode() { 61 return Objects.hash(mIsSelected, mChannelIndex, mCodecMetadata); 62 } 63 64 /** 65 * Return true if the channel is selected by Broadcast Assistant for the Broadcast Sink. 66 * 67 * Used by Broadcast Assistant and Sink, but not Broadcast Source 68 * 69 * @return true if the channel is selected by Broadcast Assistant for the Broadcast Sink 70 * @hide 71 */ 72 @SystemApi isSelected()73 public boolean isSelected() { 74 return mIsSelected; 75 } 76 77 /** 78 * Get the Broadcast Isochronous Channel index of this Broadcast Channel. 79 * 80 * @return Broadcast Isochronous Channel index 81 * @hide 82 */ 83 @SystemApi getChannelIndex()84 public int getChannelIndex() { 85 return mChannelIndex; 86 } 87 88 /** 89 * Return the codec specific configuration for this Broadcast Channel. 90 * 91 * @return codec specific configuration for this Broadcast Channel 92 * @hide 93 */ 94 @SystemApi getCodecMetadata()95 public @NonNull BluetoothLeAudioCodecConfigMetadata getCodecMetadata() { 96 return mCodecMetadata; 97 } 98 99 /** 100 * {@inheritDoc} 101 * @hide 102 */ 103 @Override describeContents()104 public int describeContents() { 105 return 0; 106 } 107 108 /** 109 * {@inheritDoc} 110 * @hide 111 */ 112 @Override writeToParcel(Parcel out, int flags)113 public void writeToParcel(Parcel out, int flags) { 114 out.writeBoolean(mIsSelected); 115 out.writeInt(mChannelIndex); 116 out.writeTypedObject(mCodecMetadata, 0); 117 } 118 119 /** 120 * A {@link Parcelable.Creator} to create {@link BluetoothLeBroadcastChannel} from parcel. 121 * @hide 122 */ 123 @SystemApi 124 public static final @NonNull Parcelable.Creator<BluetoothLeBroadcastChannel> CREATOR = 125 new Parcelable.Creator<BluetoothLeBroadcastChannel>() { 126 public @NonNull BluetoothLeBroadcastChannel createFromParcel(@NonNull Parcel in) { 127 BluetoothLeBroadcastChannel.Builder 128 builder = new BluetoothLeBroadcastChannel.Builder(); 129 builder.setSelected(in.readBoolean()); 130 builder.setChannelIndex(in.readInt()); 131 builder.setCodecMetadata( 132 in.readTypedObject(BluetoothLeAudioCodecConfigMetadata.CREATOR)); 133 return builder.build(); 134 } 135 136 public @NonNull BluetoothLeBroadcastChannel[] newArray(int size) { 137 return new BluetoothLeBroadcastChannel[size]; 138 } 139 }; 140 141 /** 142 * Builder for {@link BluetoothLeBroadcastChannel}. 143 * @hide 144 */ 145 @SystemApi 146 public static final class Builder { 147 private boolean mIsSelected = false; 148 private int mChannelIndex = UNKNOWN_VALUE_PLACEHOLDER; 149 private BluetoothLeAudioCodecConfigMetadata mCodecMetadata = null; 150 151 /** 152 * Create an empty builder. 153 * @hide 154 */ 155 @SystemApi Builder()156 public Builder() {} 157 158 /** 159 * Create a builder with copies of information from original object. 160 * 161 * @param original original object 162 * @hide 163 */ 164 @SystemApi Builder(@onNull BluetoothLeBroadcastChannel original)165 public Builder(@NonNull BluetoothLeBroadcastChannel original) { 166 mIsSelected = original.isSelected(); 167 mChannelIndex = original.getChannelIndex(); 168 mCodecMetadata = original.getCodecMetadata(); 169 } 170 171 /** 172 * Set if the channel is selected by Broadcast Assistant for the Broadcast Sink. 173 * 174 * Used by Broadcast Assistant and Sink, but not Broadcast Source 175 * 176 * @param isSelected true if the channel is selected by Broadcast Assistant for the 177 * Broadcast Sink 178 * @return this builder 179 * @hide 180 */ 181 @SystemApi setSelected(boolean isSelected)182 public @NonNull Builder setSelected(boolean isSelected) { 183 mIsSelected = isSelected; 184 return this; 185 } 186 187 /** 188 * Set the Broadcast Isochronous Channel index of this Broadcast Channel. 189 * 190 * @param channelIndex Broadcast Isochronous Channel index 191 * @throws IllegalArgumentException if the input argument is not valid 192 * @return this builder 193 * @hide 194 */ 195 @SystemApi setChannelIndex(int channelIndex)196 public @NonNull Builder setChannelIndex(int channelIndex) { 197 if (channelIndex == UNKNOWN_VALUE_PLACEHOLDER) { 198 throw new IllegalArgumentException("channelIndex cannot be " 199 + UNKNOWN_VALUE_PLACEHOLDER); 200 } 201 mChannelIndex = channelIndex; 202 return this; 203 } 204 205 /** 206 * Set the codec specific configuration for this Broadcast Channel. 207 * 208 * @param codecMetadata codec specific configuration for this Broadcast Channel 209 * @throws NullPointerException if codecMetadata is null 210 * @return this builder 211 * @hide 212 */ 213 @SystemApi setCodecMetadata( @onNull BluetoothLeAudioCodecConfigMetadata codecMetadata)214 public @NonNull Builder setCodecMetadata( 215 @NonNull BluetoothLeAudioCodecConfigMetadata codecMetadata) { 216 Objects.requireNonNull(codecMetadata, "codecMetadata cannot be null"); 217 mCodecMetadata = codecMetadata; 218 return this; 219 } 220 221 /** 222 * Build {@link BluetoothLeBroadcastChannel}. 223 * 224 * @return constructed {@link BluetoothLeBroadcastChannel} 225 * @throws NullPointerException if {@link NonNull} items are null 226 * @throws IllegalArgumentException if the object cannot be built 227 * @hide 228 */ 229 @SystemApi build()230 public @NonNull BluetoothLeBroadcastChannel build() { 231 Objects.requireNonNull(mCodecMetadata, "codec metadata cannot be null"); 232 if (mChannelIndex == UNKNOWN_VALUE_PLACEHOLDER) { 233 throw new IllegalArgumentException("mChannelIndex cannot be " 234 + UNKNOWN_VALUE_PLACEHOLDER); 235 } 236 return new BluetoothLeBroadcastChannel(mIsSelected, mChannelIndex, mCodecMetadata); 237 } 238 } 239 } 240