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.FlaggedApi; 20 import android.annotation.IntDef; 21 import android.annotation.IntRange; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.SystemApi; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 28 import com.android.bluetooth.flags.Flags; 29 30 import java.lang.annotation.Retention; 31 import java.lang.annotation.RetentionPolicy; 32 import java.util.ArrayList; 33 import java.util.Arrays; 34 import java.util.List; 35 import java.util.Objects; 36 37 /** 38 * This class represents a Broadcast Source group and the associated information that is needed by 39 * Broadcast Audio Scan Service (BASS) to set up a Broadcast Sink. 40 * 41 * <p>For example, an LE Audio Broadcast Sink can use the information contained within an instance 42 * of this class to synchronize with an LE Audio Broadcast group in order to listen to audio from 43 * Broadcast subgroup using one or more Broadcast Channels. 44 * 45 * @hide 46 */ 47 @SystemApi 48 public final class BluetoothLeBroadcastMetadata implements Parcelable { 49 // Information needed for adding broadcast Source 50 51 // Optional: Identity address type 52 private final @BluetoothDevice.AddressType int mSourceAddressType; 53 // Optional: Must use identity address 54 private final BluetoothDevice mSourceDevice; 55 private final int mSourceAdvertisingSid; 56 private final int mBroadcastId; 57 private final int mPaSyncInterval; 58 private final boolean mIsEncrypted; 59 private final boolean mIsPublicBroadcast; 60 private final String mBroadcastName; 61 private final byte[] mBroadcastCode; 62 private final BluetoothLeAudioContentMetadata mPublicBroadcastMetadata; 63 private final @AudioConfigQuality int mAudioConfigQuality; 64 private final int mRssi; 65 66 /** 67 * Audio configuration quality for this Broadcast Group. This quality bitmap is used for 68 * presenting the audio stream quality for this BIG, either public broadcast or non-public 69 * broadcast Bit0 indicates at least one broadcast Audio Stream configuration is standard 70 * quality Bit1 indicates at least one broadcast Audio Stream configuration is high quality 71 * 72 * @hide 73 */ 74 @IntDef( 75 flag = true, 76 prefix = "AUDIO_CONFIG_QUALITY_", 77 value = { 78 AUDIO_CONFIG_QUALITY_NONE, 79 AUDIO_CONFIG_QUALITY_STANDARD, 80 AUDIO_CONFIG_QUALITY_HIGH, 81 }) 82 @Retention(RetentionPolicy.SOURCE) 83 public @interface AudioConfigQuality {} 84 85 /** 86 * Audio config quality is none, default value used for audio config quality. 87 * 88 * @hide 89 */ 90 @SystemApi public static final int AUDIO_CONFIG_QUALITY_NONE = 0; 91 92 /** 93 * Audio config quality is standard. This indicates the BIG shall include at least one broadcast 94 * Audio Stream configuration defined as Mandatory for a Broadcast Sink in Basic Audio Profile, 95 * Version 1 or later, table 6.4 96 * 97 * @hide 98 */ 99 @SystemApi public static final int AUDIO_CONFIG_QUALITY_STANDARD = 0x1 << 0; 100 101 /** 102 * Audio config quality is standard. This indicates the BIG shall include at least one broadcast 103 * Audio Stream configuration setting listed in Public Broadcast Profile, Version 1 or later, 104 * table 4.2 105 * 106 * @hide 107 */ 108 @SystemApi public static final int AUDIO_CONFIG_QUALITY_HIGH = 0x1 << 1; 109 110 // BASE structure 111 112 // See Section 7 for description. Range: 0x000000 – 0xFFFFFF Units: μs 113 // All other values: RFU 114 private final int mPresentationDelayMicros; 115 // Number of subgroups used to group BISes present in the BIG 116 // Shall be at least 1, as defined by Rule 1 117 // Sub group info numSubGroup = mSubGroups.length 118 private final List<BluetoothLeBroadcastSubgroup> mSubgroups; 119 BluetoothLeBroadcastMetadata( int sourceAddressType, BluetoothDevice sourceDevice, int sourceAdvertisingSid, int broadcastId, int paSyncInterval, boolean isEncrypted, boolean isPublicBroadcast, String broadcastName, byte[] broadcastCode, int presentationDelay, @AudioConfigQuality int audioConfigQuality, int rssi, BluetoothLeAudioContentMetadata publicBroadcastMetadata, List<BluetoothLeBroadcastSubgroup> subgroups)120 private BluetoothLeBroadcastMetadata( 121 int sourceAddressType, 122 BluetoothDevice sourceDevice, 123 int sourceAdvertisingSid, 124 int broadcastId, 125 int paSyncInterval, 126 boolean isEncrypted, 127 boolean isPublicBroadcast, 128 String broadcastName, 129 byte[] broadcastCode, 130 int presentationDelay, 131 @AudioConfigQuality int audioConfigQuality, 132 int rssi, 133 BluetoothLeAudioContentMetadata publicBroadcastMetadata, 134 List<BluetoothLeBroadcastSubgroup> subgroups) { 135 mSourceAddressType = sourceAddressType; 136 mSourceDevice = sourceDevice; 137 mSourceAdvertisingSid = sourceAdvertisingSid; 138 mBroadcastId = broadcastId; 139 mPaSyncInterval = paSyncInterval; 140 mIsEncrypted = isEncrypted; 141 mIsPublicBroadcast = isPublicBroadcast; 142 mBroadcastName = broadcastName; 143 mBroadcastCode = broadcastCode; 144 mPresentationDelayMicros = presentationDelay; 145 mAudioConfigQuality = audioConfigQuality; 146 mRssi = rssi; 147 mPublicBroadcastMetadata = publicBroadcastMetadata; 148 mSubgroups = subgroups; 149 } 150 151 @Override equals(@ullable Object o)152 public boolean equals(@Nullable Object o) { 153 if (!(o instanceof BluetoothLeBroadcastMetadata)) { 154 return false; 155 } 156 final BluetoothLeBroadcastMetadata other = (BluetoothLeBroadcastMetadata) o; 157 return mSourceAddressType == other.getSourceAddressType() 158 && mSourceDevice.equals(other.getSourceDevice()) 159 && mSourceAdvertisingSid == other.getSourceAdvertisingSid() 160 && mBroadcastId == other.getBroadcastId() 161 && mPaSyncInterval == other.getPaSyncInterval() 162 && mIsEncrypted == other.isEncrypted() 163 && mIsPublicBroadcast == other.isPublicBroadcast() 164 && Objects.equals(mBroadcastName, other.getBroadcastName()) 165 && Arrays.equals(mBroadcastCode, other.getBroadcastCode()) 166 && mPresentationDelayMicros == other.getPresentationDelayMicros() 167 && mAudioConfigQuality == other.getAudioConfigQuality() 168 && mRssi == other.getRssi() 169 && Objects.equals(mPublicBroadcastMetadata, other.getPublicBroadcastMetadata()) 170 && mSubgroups.equals(other.getSubgroups()); 171 } 172 173 @Override hashCode()174 public int hashCode() { 175 return Objects.hash( 176 mSourceAddressType, 177 mSourceDevice, 178 mSourceAdvertisingSid, 179 mBroadcastId, 180 mPaSyncInterval, 181 mIsEncrypted, 182 mIsPublicBroadcast, 183 mBroadcastName, 184 Arrays.hashCode(mBroadcastCode), 185 mPresentationDelayMicros, 186 mAudioConfigQuality, 187 mRssi, 188 mPublicBroadcastMetadata, 189 mSubgroups); 190 } 191 192 @Override toString()193 public String toString() { 194 return "BluetoothLeBroadcastMetadata{" 195 + ("sourceAddressType=" + mSourceAddressType) 196 + (", sourceDevice=" + mSourceDevice) 197 + (", sourceAdvertisingSid=" + mSourceAdvertisingSid) 198 + (", broadcastId=" + mBroadcastId) 199 + (", paSyncInterval=" + mPaSyncInterval) 200 + (", isEncrypted=" + mIsEncrypted) 201 + (", isPublicBroadcast=" + mIsPublicBroadcast) 202 + (", broadcastName=" + mBroadcastName) 203 + (", broadcastCode=" + Arrays.toString(mBroadcastCode)) 204 + (", presentationDelayMicros=" + mPresentationDelayMicros) 205 + (", audioConfigQuality=" + mAudioConfigQuality) 206 + (", rssi=" + mRssi) 207 + (", publicBroadcastMetadata=" + mPublicBroadcastMetadata) 208 + (", subgroups=" + mSubgroups) 209 + '}'; 210 } 211 212 /** 213 * Get the address type of the Broadcast Source. 214 * 215 * <p>Can be either {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC}, {@link 216 * BluetoothDevice#ADDRESS_TYPE_RANDOM} 217 * 218 * @return address type of the Broadcast Source 219 * @hide 220 */ 221 @SystemApi getSourceAddressType()222 public @BluetoothDevice.AddressType int getSourceAddressType() { 223 return mSourceAddressType; 224 } 225 226 /** 227 * Get the MAC address of the Broadcast Source, which can be Public Device Address, Random 228 * Device Address, Public Identity Address or Random (static) Identity Address. 229 * 230 * @return MAC address of the Broadcast Source 231 * @hide 232 */ 233 @SystemApi getSourceDevice()234 public @NonNull BluetoothDevice getSourceDevice() { 235 return mSourceDevice; 236 } 237 238 /** 239 * Get Advertising_SID subfield of the ADI field of the AUX_ADV_IND PDU or the 240 * LL_PERIODIC_SYNC_IND containing the SyncInfo that points to the PA transmitted by the 241 * Broadcast Source. 242 * 243 * @return 1-byte long Advertising_SID of the Broadcast Source 244 * @hide 245 */ 246 @SystemApi getSourceAdvertisingSid()247 public int getSourceAdvertisingSid() { 248 return mSourceAdvertisingSid; 249 } 250 251 /** 252 * Broadcast_ID of the Broadcast Source. 253 * 254 * @return 3-byte long Broadcast_ID of the Broadcast Source 255 * @hide 256 */ 257 @SystemApi getBroadcastId()258 public int getBroadcastId() { 259 return mBroadcastId; 260 } 261 262 /** 263 * Indicated that Periodic Advertising Sync interval is unknown. 264 * 265 * @hide 266 */ 267 @SystemApi public static final int PA_SYNC_INTERVAL_UNKNOWN = 0xFFFF; 268 269 /** 270 * Get Periodic Advertising Sync interval of the broadcast Source. 271 * 272 * @return Periodic Advertising Sync interval of the broadcast Source, {@link 273 * #PA_SYNC_INTERVAL_UNKNOWN} if unknown 274 * @hide 275 */ 276 @SystemApi getPaSyncInterval()277 public int getPaSyncInterval() { 278 return mPaSyncInterval; 279 } 280 281 /** 282 * Return true if the Broadcast Source is encrypted. 283 * 284 * @return true if the Broadcast Source is encrypted 285 * @hide 286 */ 287 @SystemApi isEncrypted()288 public boolean isEncrypted() { 289 return mIsEncrypted; 290 } 291 292 /** 293 * Return {@code true} if this Broadcast Group is broadcasting Public Broadcast Announcement 294 * otherwise return {@code false}. 295 * 296 * @hide 297 */ 298 @SystemApi isPublicBroadcast()299 public boolean isPublicBroadcast() { 300 return mIsPublicBroadcast; 301 } 302 303 /** 304 * Get the broadcast name for this Broadcast Group as UTF-8 format. 305 * 306 * @return broadcast name or null for this Broadcast Group 307 * @hide 308 */ 309 @SystemApi getBroadcastName()310 public @Nullable String getBroadcastName() { 311 return mBroadcastName; 312 } 313 314 /** 315 * Get the Broadcast Code currently set for this Broadcast Source. 316 * 317 * <p>Only needed when encryption is enabled 318 * 319 * <p>As defined in Volume 3, Part C, Section 3.2.6 of Bluetooth Core Specification, Version 320 * 5.3, Broadcast Code is used to encrypt a broadcast audio stream. 321 * 322 * <p>It must be a UTF-8 string that has at least 4 octets and should not exceed 16 octets. 323 * 324 * @return Broadcast Code currently set for this Broadcast Source, {@code null} if code is not 325 * required or code is currently unknown 326 * @hide 327 */ 328 @SystemApi getBroadcastCode()329 public @Nullable byte[] getBroadcastCode() { 330 return mBroadcastCode; 331 } 332 333 /** 334 * Get the overall presentation delay in microseconds of this Broadcast Source. 335 * 336 * <p>Presentation delay is defined in Section 7 of the Basic Audio Profile. 337 * 338 * @return presentation delay of this Broadcast Source in microseconds 339 * @hide 340 */ 341 @SystemApi getPresentationDelayMicros()342 public @IntRange(from = 0, to = 0xFFFFFF) int getPresentationDelayMicros() { 343 return mPresentationDelayMicros; 344 } 345 346 /** 347 * Get broadcast audio config quality for this Broadcast Group. 348 * 349 * @return Broadcast audio config quality for this Broadcast Group 350 * @hide 351 */ 352 @SystemApi getAudioConfigQuality()353 public @AudioConfigQuality int getAudioConfigQuality() { 354 return mAudioConfigQuality; 355 } 356 357 /** 358 * Indicated that rssi value is unknown. 359 * 360 * @hide 361 */ 362 @FlaggedApi(Flags.FLAG_LEAUDIO_BROADCAST_MONITOR_SOURCE_SYNC_STATUS) 363 @SystemApi 364 public static final int RSSI_UNKNOWN = 0x7F; 365 366 /** 367 * Get the Received Signal Strength Indication (RSSI) value of this Broadcast Source. 368 * 369 * <p>The valid RSSI range is [-127, 126] and as defined in Volume 4, Part E, Section 7.7.65.13 370 * of Bluetooth Core Specification, Version 5.3, value of 0x7F(127) means that the RSSI is not 371 * available. 372 * 373 * @return the RSSI {@link #RSSI_UNKNOWN} if unknown 374 * @hide 375 */ 376 @FlaggedApi(Flags.FLAG_LEAUDIO_BROADCAST_MONITOR_SOURCE_SYNC_STATUS) 377 @SystemApi getRssi()378 public @IntRange(from = -127, to = 127) int getRssi() { 379 return mRssi; 380 } 381 382 /** 383 * Get public broadcast metadata for this Broadcast Group. 384 * 385 * @return public broadcast metadata for this Broadcast Group, {@code null} if no public 386 * metadata exists 387 * @hide 388 */ 389 @SystemApi getPublicBroadcastMetadata()390 public @Nullable BluetoothLeAudioContentMetadata getPublicBroadcastMetadata() { 391 return mPublicBroadcastMetadata; 392 } 393 394 /** 395 * Get available subgroups in this broadcast source. 396 * 397 * @return list of subgroups in this broadcast source, which should contain at least one 398 * subgroup for each Broadcast Source 399 * @hide 400 */ 401 @SystemApi getSubgroups()402 public @NonNull List<BluetoothLeBroadcastSubgroup> getSubgroups() { 403 return mSubgroups; 404 } 405 406 /** 407 * {@inheritDoc} 408 * 409 * @hide 410 */ 411 @Override describeContents()412 public int describeContents() { 413 return 0; 414 } 415 416 /** 417 * {@inheritDoc} 418 * 419 * @hide 420 */ 421 @Override writeToParcel(Parcel out, int flags)422 public void writeToParcel(Parcel out, int flags) { 423 out.writeInt(mSourceAddressType); 424 if (mSourceDevice != null) { 425 out.writeInt(1); 426 out.writeTypedObject(mSourceDevice, 0); 427 } else { 428 // zero indicates missing mSourceDevice 429 out.writeInt(0); 430 } 431 out.writeInt(mSourceAdvertisingSid); 432 out.writeInt(mBroadcastId); 433 out.writeInt(mPaSyncInterval); 434 out.writeBoolean(mIsEncrypted); 435 if (mBroadcastCode != null) { 436 out.writeInt(mBroadcastCode.length); 437 out.writeByteArray(mBroadcastCode); 438 } else { 439 // -1 indicates missing broadcast code 440 out.writeInt(-1); 441 } 442 out.writeInt(mPresentationDelayMicros); 443 out.writeTypedList(mSubgroups); 444 out.writeBoolean(mIsPublicBroadcast); 445 out.writeString(mBroadcastName); 446 out.writeInt(mAudioConfigQuality); 447 out.writeTypedObject(mPublicBroadcastMetadata, 0); 448 out.writeInt(mRssi); 449 } 450 451 /** 452 * A {@link Parcelable.Creator} to create {@link BluetoothLeBroadcastMetadata} from parcel. 453 * 454 * @hide 455 */ 456 @SystemApi @NonNull 457 public static final Creator<BluetoothLeBroadcastMetadata> CREATOR = 458 new Creator<>() { 459 public @NonNull BluetoothLeBroadcastMetadata createFromParcel(@NonNull Parcel in) { 460 Builder builder = new Builder(); 461 final int sourceAddressType = in.readInt(); 462 final int deviceExist = in.readInt(); 463 BluetoothDevice sourceDevice = null; 464 if (deviceExist == 1) { 465 sourceDevice = in.readTypedObject(BluetoothDevice.CREATOR); 466 } 467 builder.setSourceDevice(sourceDevice, sourceAddressType); 468 builder.setSourceAdvertisingSid(in.readInt()); 469 builder.setBroadcastId(in.readInt()); 470 builder.setPaSyncInterval(in.readInt()); 471 builder.setEncrypted(in.readBoolean()); 472 final int codeLen = in.readInt(); 473 byte[] broadcastCode = null; 474 if (codeLen != -1) { 475 broadcastCode = new byte[codeLen]; 476 if (codeLen >= 0) { 477 in.readByteArray(broadcastCode); 478 } 479 } 480 builder.setBroadcastCode(broadcastCode); 481 builder.setPresentationDelayMicros(in.readInt()); 482 final List<BluetoothLeBroadcastSubgroup> subgroups = new ArrayList<>(); 483 in.readTypedList(subgroups, BluetoothLeBroadcastSubgroup.CREATOR); 484 for (BluetoothLeBroadcastSubgroup subgroup : subgroups) { 485 builder.addSubgroup(subgroup); 486 } 487 builder.setPublicBroadcast(in.readBoolean()); 488 builder.setBroadcastName(in.readString()); 489 builder.setAudioConfigQuality(in.readInt()); 490 builder.setPublicBroadcastMetadata( 491 in.readTypedObject(BluetoothLeAudioContentMetadata.CREATOR)); 492 builder.setRssi(in.readInt()); 493 return builder.build(); 494 } 495 496 public @NonNull BluetoothLeBroadcastMetadata[] newArray(int size) { 497 return new BluetoothLeBroadcastMetadata[size]; 498 } 499 }; 500 501 private static final int UNKNOWN_VALUE_PLACEHOLDER = -1; 502 503 /** 504 * Builder for {@link BluetoothLeBroadcastMetadata}. 505 * 506 * @hide 507 */ 508 @SystemApi 509 public static final class Builder { 510 private @BluetoothDevice.AddressType int mSourceAddressType = 511 BluetoothDevice.ADDRESS_TYPE_UNKNOWN; 512 private BluetoothDevice mSourceDevice = null; 513 private int mSourceAdvertisingSid = UNKNOWN_VALUE_PLACEHOLDER; 514 private int mBroadcastId = UNKNOWN_VALUE_PLACEHOLDER; 515 private int mPaSyncInterval = PA_SYNC_INTERVAL_UNKNOWN; 516 private boolean mIsEncrypted = false; 517 private boolean mIsPublicBroadcast = false; 518 private String mBroadcastName = null; 519 private byte[] mBroadcastCode = null; 520 private int mPresentationDelayMicros = UNKNOWN_VALUE_PLACEHOLDER; 521 private @AudioConfigQuality int mAudioConfigQuality = AUDIO_CONFIG_QUALITY_NONE; 522 private int mRssi = RSSI_UNKNOWN; 523 private BluetoothLeAudioContentMetadata mPublicBroadcastMetadata = null; 524 private List<BluetoothLeBroadcastSubgroup> mSubgroups = new ArrayList<>(); 525 526 /** 527 * Create an empty builder. 528 * 529 * @hide 530 */ 531 @SystemApi Builder()532 public Builder() {} 533 534 /** 535 * Create a builder with copies of information from original object. 536 * 537 * @param original original object 538 * @hide 539 */ 540 @SystemApi Builder(@onNull BluetoothLeBroadcastMetadata original)541 public Builder(@NonNull BluetoothLeBroadcastMetadata original) { 542 mSourceAddressType = original.getSourceAddressType(); 543 mSourceDevice = original.getSourceDevice(); 544 mSourceAdvertisingSid = original.getSourceAdvertisingSid(); 545 mBroadcastId = original.getBroadcastId(); 546 mPaSyncInterval = original.getPaSyncInterval(); 547 mIsEncrypted = original.isEncrypted(); 548 mIsPublicBroadcast = original.isPublicBroadcast(); 549 mBroadcastName = original.getBroadcastName(); 550 mBroadcastCode = original.getBroadcastCode(); 551 mPresentationDelayMicros = original.getPresentationDelayMicros(); 552 mAudioConfigQuality = original.getAudioConfigQuality(); 553 mRssi = original.getRssi(); 554 mPublicBroadcastMetadata = original.getPublicBroadcastMetadata(); 555 mSubgroups = original.getSubgroups(); 556 } 557 558 /** 559 * Set the address type and MAC address of the Broadcast Source. 560 * 561 * <p>Address type can be either {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC}, {@link 562 * BluetoothDevice#ADDRESS_TYPE_RANDOM} 563 * 564 * <p>MAC address can be Public Device Address, Random Device Address, Public Identity 565 * Address or Random (static) Identity Address 566 * 567 * @param sourceDevice source advertiser address 568 * @param sourceAddressType source advertiser address type 569 * @throws IllegalArgumentException if sourceAddressType is invalid 570 * @throws NullPointerException if sourceDevice is null 571 * @return this builder 572 * @hide 573 */ 574 @SystemApi 575 @NonNull setSourceDevice( @onNull BluetoothDevice sourceDevice, @BluetoothDevice.AddressType int sourceAddressType)576 public Builder setSourceDevice( 577 @NonNull BluetoothDevice sourceDevice, 578 @BluetoothDevice.AddressType int sourceAddressType) { 579 if (sourceAddressType == BluetoothDevice.ADDRESS_TYPE_UNKNOWN) { 580 throw new IllegalArgumentException( 581 "sourceAddressType cannot be ADDRESS_TYPE_UNKNOWN"); 582 } 583 if (sourceAddressType != BluetoothDevice.ADDRESS_TYPE_RANDOM 584 && sourceAddressType != BluetoothDevice.ADDRESS_TYPE_PUBLIC) { 585 throw new IllegalArgumentException( 586 "sourceAddressType " + sourceAddressType + " is invalid"); 587 } 588 Objects.requireNonNull(sourceDevice, "sourceDevice cannot be null"); 589 mSourceAddressType = sourceAddressType; 590 mSourceDevice = sourceDevice; 591 return this; 592 } 593 594 /** 595 * Set Advertising_SID that is a subfield of the ADI field of the AUX_ADV_IND PDU or the 596 * LL_PERIODIC_SYNC_IND containing the SyncInfo that points to the PA transmitted by the 597 * Broadcast Source. 598 * 599 * @param sourceAdvertisingSid 1-byte long Advertising_SID of the Broadcast Source 600 * @return this builder 601 * @hide 602 */ 603 @SystemApi setSourceAdvertisingSid(int sourceAdvertisingSid)604 public @NonNull Builder setSourceAdvertisingSid(int sourceAdvertisingSid) { 605 mSourceAdvertisingSid = sourceAdvertisingSid; 606 return this; 607 } 608 609 /** 610 * Set the Broadcast_ID of the Broadcast Source. 611 * 612 * @param broadcastId 3-byte long Broadcast_ID of the Broadcast Source 613 * @return this builder 614 * @hide 615 */ 616 @SystemApi setBroadcastId(int broadcastId)617 public @NonNull Builder setBroadcastId(int broadcastId) { 618 mBroadcastId = broadcastId; 619 return this; 620 } 621 622 /** 623 * Set Periodic Advertising Sync interval of the broadcast Source. 624 * 625 * @param paSyncInterval Periodic Advertising Sync interval of the broadcast Source, {@link 626 * #PA_SYNC_INTERVAL_UNKNOWN} if unknown 627 * @return this builder 628 * @hide 629 */ 630 @SystemApi setPaSyncInterval(int paSyncInterval)631 public @NonNull Builder setPaSyncInterval(int paSyncInterval) { 632 mPaSyncInterval = paSyncInterval; 633 return this; 634 } 635 636 /** 637 * Set whether the Broadcast Source should be encrypted. 638 * 639 * <p>When setting up a Broadcast Source, if <var>isEncrypted</var> is true while 640 * <var>broadcastCode</var> is null, the implementation will automatically generate a 641 * Broadcast Code 642 * 643 * @param isEncrypted whether the Broadcast Source is encrypted 644 * @return this builder 645 * @hide 646 */ 647 @SystemApi setEncrypted(boolean isEncrypted)648 public @NonNull Builder setEncrypted(boolean isEncrypted) { 649 mIsEncrypted = isEncrypted; 650 return this; 651 } 652 653 /** 654 * Set whether this Broadcast Group is broadcasting Public Broadcast Announcement. 655 * 656 * @param isPublicBroadcast whether this Broadcast Group is broadcasting Public Broadcast 657 * Announcement 658 * @return this builder 659 * @hide 660 */ 661 @SystemApi setPublicBroadcast(boolean isPublicBroadcast)662 public @NonNull Builder setPublicBroadcast(boolean isPublicBroadcast) { 663 mIsPublicBroadcast = isPublicBroadcast; 664 return this; 665 } 666 667 /** 668 * Set broadcast name for this Broadcast Group. 669 * 670 * @param broadcastName Broadcast name for this Broadcast Group, {@code null} if no name 671 * provided 672 * @return this builder 673 * @hide 674 */ 675 @SystemApi setBroadcastName(@ullable String broadcastName)676 public @NonNull Builder setBroadcastName(@Nullable String broadcastName) { 677 mBroadcastName = broadcastName; 678 return this; 679 } 680 681 /** 682 * Set the Broadcast Code currently set for this broadcast group. 683 * 684 * <p>Only needed when encryption is enabled 685 * 686 * <p>As defined in Volume 3, Part C, Section 3.2.6 of Bluetooth Core Specification, Version 687 * 5.3, Broadcast Code is used to encrypt a broadcast audio stream. 688 * 689 * <p>It must be a UTF-8 string that has at least 4 octets and should not exceed 16 octets. 690 * 691 * @param broadcastCode Broadcast Code for this Broadcast Source, {@code null} if code is 692 * not required 693 * @return this builder 694 * @hide 695 */ 696 @SystemApi setBroadcastCode(@ullable byte[] broadcastCode)697 public @NonNull Builder setBroadcastCode(@Nullable byte[] broadcastCode) { 698 mBroadcastCode = broadcastCode; 699 return this; 700 } 701 702 /** 703 * Set the overall presentation delay in microseconds of this Broadcast Source. 704 * 705 * <p>Presentation delay is defined in Section 7 of the Basic Audio Profile. 706 * 707 * @param presentationDelayMicros presentation delay of this Broadcast Source in 708 * microseconds 709 * @throws IllegalArgumentException if presentationDelayMicros does not fall in [0, 710 * 0xFFFFFF] 711 * @return this builder 712 * @hide 713 */ 714 @SystemApi 715 @NonNull setPresentationDelayMicros( @ntRangefrom = 0, to = 0xFFFFFF) int presentationDelayMicros)716 public Builder setPresentationDelayMicros( 717 @IntRange(from = 0, to = 0xFFFFFF) int presentationDelayMicros) { 718 if (presentationDelayMicros < 0 || presentationDelayMicros >= 0xFFFFFF) { 719 throw new IllegalArgumentException( 720 "presentationDelayMicros " 721 + presentationDelayMicros 722 + " does not fall in [0, 0xFFFFFF]"); 723 } 724 mPresentationDelayMicros = presentationDelayMicros; 725 return this; 726 } 727 728 /** 729 * Set broadcast audio config quality for this Broadcast Group. 730 * 731 * @param audioConfigQuality broadcast audio config quality for this Broadcast Group 732 * @return this builder 733 * @hide 734 */ 735 @SystemApi 736 @NonNull setAudioConfigQuality(@udioConfigQuality int audioConfigQuality)737 public Builder setAudioConfigQuality(@AudioConfigQuality int audioConfigQuality) { 738 mAudioConfigQuality = audioConfigQuality; 739 return this; 740 } 741 742 /** 743 * Set the Received Signal Strength Indication (RSSI) value for this Broadcast metadata. 744 * 745 * <p>The valid RSSI range is [-127, 126] and as defined in Volume 4, Part E, Section 746 * 7.7.65.13 of Bluetooth Core Specification, Version 5.3, value of 0x7F(127) means that the 747 * RSSI is not available. 748 * 749 * @param rssi the RSSI 750 * @return this builder 751 * @throws IllegalArgumentException if rssi is not in the range [-127, 127]. 752 * @hide 753 */ 754 @FlaggedApi(Flags.FLAG_LEAUDIO_BROADCAST_MONITOR_SOURCE_SYNC_STATUS) 755 @SystemApi 756 @NonNull setRssi(@ntRangefrom = -127, to = 127) int rssi)757 public Builder setRssi(@IntRange(from = -127, to = 127) int rssi) { 758 if (rssi < -127 || rssi > 127) { 759 throw new IllegalArgumentException("illegal rssi " + rssi); 760 } 761 mRssi = rssi; 762 return this; 763 } 764 765 /** 766 * Set public broadcast metadata for this Broadcast Group. PBS should include the 767 * Program_Info length-type-value (LTV) structure metadata 768 * 769 * @param publicBroadcastMetadata public broadcast metadata for this Broadcast Group, {@code 770 * null} if no public meta data provided 771 * @return this builder 772 * @hide 773 */ 774 @SystemApi 775 @NonNull setPublicBroadcastMetadata( @ullable BluetoothLeAudioContentMetadata publicBroadcastMetadata)776 public Builder setPublicBroadcastMetadata( 777 @Nullable BluetoothLeAudioContentMetadata publicBroadcastMetadata) { 778 mPublicBroadcastMetadata = publicBroadcastMetadata; 779 return this; 780 } 781 782 /** 783 * Add a subgroup to this broadcast source. 784 * 785 * @param subgroup {@link BluetoothLeBroadcastSubgroup} that contains a subgroup's metadata 786 * @throws NullPointerException if subgroup is null 787 * @return this builder 788 * @hide 789 */ 790 @SystemApi addSubgroup(@onNull BluetoothLeBroadcastSubgroup subgroup)791 public @NonNull Builder addSubgroup(@NonNull BluetoothLeBroadcastSubgroup subgroup) { 792 Objects.requireNonNull(subgroup, "subgroup cannot be null"); 793 mSubgroups.add(subgroup); 794 return this; 795 } 796 797 /** 798 * Clear subgroup list so that one can reset the builder after create it from an existing 799 * object. 800 * 801 * @return this builder 802 * @hide 803 */ 804 @SystemApi clearSubgroup()805 public @NonNull Builder clearSubgroup() { 806 mSubgroups.clear(); 807 return this; 808 } 809 810 /** 811 * Build {@link BluetoothLeBroadcastMetadata}. 812 * 813 * @return {@link BluetoothLeBroadcastMetadata} 814 * @throws IllegalArgumentException if the object cannot be built 815 * @throws NullPointerException if {@link NonNull} items are null 816 * @hide 817 */ 818 @SystemApi build()819 public @NonNull BluetoothLeBroadcastMetadata build() { 820 if (mSourceAddressType == BluetoothDevice.ADDRESS_TYPE_UNKNOWN) { 821 throw new IllegalArgumentException("SourceAddressTyp cannot be unknown"); 822 } 823 if (mSourceAddressType != BluetoothDevice.ADDRESS_TYPE_RANDOM 824 && mSourceAddressType != BluetoothDevice.ADDRESS_TYPE_PUBLIC) { 825 throw new IllegalArgumentException( 826 "sourceAddressType " + mSourceAddressType + " is invalid"); 827 } 828 Objects.requireNonNull(mSourceDevice, "mSourceDevice cannot be null"); 829 if (mSubgroups.isEmpty()) { 830 throw new IllegalArgumentException("Must contain at least one subgroup"); 831 } 832 return new BluetoothLeBroadcastMetadata( 833 mSourceAddressType, 834 mSourceDevice, 835 mSourceAdvertisingSid, 836 mBroadcastId, 837 mPaSyncInterval, 838 mIsEncrypted, 839 mIsPublicBroadcast, 840 mBroadcastName, 841 mBroadcastCode, 842 mPresentationDelayMicros, 843 mAudioConfigQuality, 844 mRssi, 845 mPublicBroadcastMetadata, 846 mSubgroups); 847 } 848 } 849 } 850