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