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