• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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