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