• 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.List;
31 import java.util.Objects;
32 
33 /**
34  * The {@link BluetoothLeBroadcastReceiveState} is used by the BASS server to expose information
35  * about a Broadcast Source.
36  *
37  * It represents the current synchronization state of the server to
38  * a PA and/or a BIG containing one or more subgroups containing one or more BISes
39  * transmitted by that Broadcast Source. The Broadcast Receive State characteristic is also
40  * used to inform clients whether the server has detected that the BIS is encrypted, whether
41  * the server requires a Broadcast_Code, and whether the server is decrypting the BIS.
42  *
43  * @hide
44  */
45 @SystemApi
46 public final class BluetoothLeBroadcastReceiveState implements Parcelable {
47     /**
48      * Periodic Advertising Synchronization state.
49      *
50      * <p>Periodic Advertising (PA) enables the LE Audio Broadcast Assistant to discover broadcast
51      * audio streams as well as the audio stream configuration on behalf of an LE Audio Broadcast
52      * Sink. This information can then be transferred to the LE Audio Broadcast Sink using the
53      * Periodic Advertising Synchronization Transfer (PAST) procedure.
54      *
55      * @hide
56      */
57     @IntDef(prefix = "PA_SYNC_STATE_",
58             value = {
59                     PA_SYNC_STATE_IDLE,
60                     PA_SYNC_STATE_SYNCINFO_REQUEST,
61                     PA_SYNC_STATE_SYNCHRONIZED,
62                     PA_SYNC_STATE_FAILED_TO_SYNCHRONIZE,
63                     PA_SYNC_STATE_NO_PAST
64             })
65     @Retention(RetentionPolicy.SOURCE)
66     public @interface PaSyncState {}
67 
68     /**
69      * Indicates that the Broadcast Sink is not synchronized with the Periodic Advertisements (PA)
70      *
71      * @hide
72      */
73     @SystemApi
74     public static final int PA_SYNC_STATE_IDLE = 0;
75 
76     /**
77      * Indicates that the Broadcast Sink requested the Broadcast Assistant to synchronize with the
78      * Periodic Advertisements (PA).
79      *
80      * <p>This is also known as scan delegation or scan offloading.
81      *
82      * @hide
83      */
84     @SystemApi
85     public static final int PA_SYNC_STATE_SYNCINFO_REQUEST = 1;
86 
87     /**
88      * Indicates that the Broadcast Sink is synchronized with the Periodic Advertisements (PA).
89      *
90      * @hide
91      */
92     @SystemApi
93     public static final int PA_SYNC_STATE_SYNCHRONIZED = 2;
94 
95     /**
96      * Indicates that the Broadcast Sink was unable to synchronize with the Periodic Advertisements
97      * (PA).
98      *
99      * @hide
100      */
101     @SystemApi
102     public static final int PA_SYNC_STATE_FAILED_TO_SYNCHRONIZE = 3;
103 
104     /**
105      * Indicates that the Broadcast Sink should be synchronized with the Periodic Advertisements
106      * (PA) using the Periodic Advertisements Synchronization Transfer (PAST) procedure.
107      *
108      * @hide
109      */
110     @SystemApi
111     public static final int PA_SYNC_STATE_NO_PAST = 4;
112 
113     /**
114      * Indicates that the Broadcast Sink synchronization state is invalid.
115      *
116      * @hide
117      */
118     public static final int PA_SYNC_STATE_INVALID = 0xFFFF;
119 
120     /** @hide */
121     @IntDef(
122             prefix = "BIG_ENCRYPTION_STATE_",
123             value = {
124                     BIG_ENCRYPTION_STATE_NOT_ENCRYPTED,
125                     BIG_ENCRYPTION_STATE_CODE_REQUIRED,
126                     BIG_ENCRYPTION_STATE_DECRYPTING,
127                     BIG_ENCRYPTION_STATE_BAD_CODE
128             })
129     @Retention(RetentionPolicy.SOURCE)
130     public @interface BigEncryptionState {}
131 
132     /**
133      * Indicates that the Broadcast Sink is synchronized with an unencrypted audio stream from a
134      * Broadcast Source
135      *
136      * @hide
137      */
138     @SystemApi
139     public static final int BIG_ENCRYPTION_STATE_NOT_ENCRYPTED = 0;
140 
141     /**
142      * Indicates that the Broadcast Sink needs a Broadcast Code to synchronize with an audio stream
143      * from a Broadcast Source, which was not provided when the audio stream from the Broadcast
144      * Source was added.
145      *
146      * @hide
147      */
148     @SystemApi
149     public static final int BIG_ENCRYPTION_STATE_CODE_REQUIRED = 1;
150 
151     /**
152      * Indicates that the Broadcast Sink is synchronized with an encrypted audio stream from a
153      * Broadcast Source.
154      *
155      * @hide
156      */
157     @SystemApi
158     public static final int BIG_ENCRYPTION_STATE_DECRYPTING = 2;
159 
160     /**
161      * Indicates that the Broadcast Sink is unable to decrypt an audio stream from a Broadcast
162      * Source due to an incorrect Broadcast Code.
163      *
164      * @hide
165      */
166     @SystemApi
167     public static final int BIG_ENCRYPTION_STATE_BAD_CODE = 3;
168 
169     /**
170      * Indicates that the Broadcast Sink encryption state is invalid.
171      *
172      * @hide
173      */
174     public static final int BIG_ENCRYPTION_STATE_INVALID = 0xFFFF;
175 
176     private final int mSourceId;
177     private final @BluetoothDevice.AddressType int mSourceAddressType;
178     private final BluetoothDevice mSourceDevice;
179     private final int mSourceAdvertisingSid;
180     private final int mBroadcastId;
181     private final @PaSyncState int mPaSyncState;
182     private final @BigEncryptionState int mBigEncryptionState;
183     private final byte[] mBadCode;
184     private final int mNumSubgroups;
185     private final List<Long> mBisSyncState;
186     private final List<BluetoothLeAudioContentMetadata> mSubgroupMetadata;
187 
188     /**
189      * Constructor to create a read-only {@link BluetoothLeBroadcastReceiveState} instance.
190      *
191      * @throws NullPointerException if sourceDevice, bisSyncState, or subgroupMetadata is null
192      * @throws IllegalArgumentException if sourceID is not [0, 0xFF] or if sourceAddressType
193      *      is invalid or if bisSyncState.size() != numSubgroups or if subgroupMetadata.size() !=
194      *      numSubgroups or if paSyncState or bigEncryptionState is not recognized bye IntDef
195      * @hide
196      */
BluetoothLeBroadcastReceiveState(@ntRangefrom = 0x00, to = 0xFF) int sourceId, @BluetoothDevice.AddressType int sourceAddressType, @NonNull BluetoothDevice sourceDevice, int sourceAdvertisingSid, int broadcastId, @PaSyncState int paSyncState, @BigEncryptionState int bigEncryptionState, byte[] badCode, @IntRange(from = 0x00) int numSubgroups, @NonNull List<Long> bisSyncState, @NonNull List<BluetoothLeAudioContentMetadata> subgroupMetadata)197     public BluetoothLeBroadcastReceiveState(@IntRange(from = 0x00, to = 0xFF) int sourceId,
198             @BluetoothDevice.AddressType int sourceAddressType,
199             @NonNull BluetoothDevice sourceDevice, int sourceAdvertisingSid, int broadcastId,
200             @PaSyncState int paSyncState, @BigEncryptionState int bigEncryptionState,
201             byte[] badCode, @IntRange(from = 0x00) int numSubgroups,
202             @NonNull List<Long> bisSyncState,
203             @NonNull List<BluetoothLeAudioContentMetadata> subgroupMetadata) {
204         if (sourceId < 0x00 || sourceId > 0xFF) {
205             throw new IllegalArgumentException("sourceId " + sourceId
206                     + " does not fall between 0x00 and 0xFF");
207         }
208         Objects.requireNonNull(sourceDevice, "sourceDevice cannot be null");
209         if (sourceAddressType == BluetoothDevice.ADDRESS_TYPE_UNKNOWN) {
210             throw new IllegalArgumentException("sourceAddressType cannot be ADDRESS_TYPE_UNKNOWN");
211         }
212         if (sourceAddressType != BluetoothDevice.ADDRESS_TYPE_RANDOM
213                 && sourceAddressType != BluetoothDevice.ADDRESS_TYPE_PUBLIC) {
214             throw new IllegalArgumentException("sourceAddressType " + sourceAddressType
215                     + " is invalid");
216         }
217         Objects.requireNonNull(bisSyncState, "bisSyncState cannot be null");
218         if (bisSyncState.size() != numSubgroups) {
219             throw new IllegalArgumentException("bisSyncState.size() " + bisSyncState.size()
220                     + " must be equal to numSubgroups " + numSubgroups);
221         }
222         Objects.requireNonNull(subgroupMetadata, "subgroupMetadata cannot be null");
223         if (subgroupMetadata.size() != numSubgroups) {
224             throw new IllegalArgumentException("subgroupMetadata.size()  "
225                     + subgroupMetadata.size() + " must be equal to numSubgroups " + numSubgroups);
226         }
227         if (paSyncState != PA_SYNC_STATE_IDLE
228                 && paSyncState != PA_SYNC_STATE_SYNCINFO_REQUEST
229                 && paSyncState != PA_SYNC_STATE_SYNCHRONIZED
230                 && paSyncState != PA_SYNC_STATE_FAILED_TO_SYNCHRONIZE
231                 && paSyncState != PA_SYNC_STATE_NO_PAST
232                 && paSyncState != PA_SYNC_STATE_INVALID) {
233             throw new IllegalArgumentException("unrecognized paSyncState " + paSyncState);
234         }
235         if (bigEncryptionState != BIG_ENCRYPTION_STATE_NOT_ENCRYPTED
236                 && bigEncryptionState != BIG_ENCRYPTION_STATE_CODE_REQUIRED
237                 && bigEncryptionState != BIG_ENCRYPTION_STATE_DECRYPTING
238                 && bigEncryptionState != BIG_ENCRYPTION_STATE_BAD_CODE
239                 && bigEncryptionState != BIG_ENCRYPTION_STATE_INVALID) {
240             throw new IllegalArgumentException("unrecognized bigEncryptionState "
241                     + bigEncryptionState);
242         }
243         if (badCode != null && badCode.length != 16) {
244             throw new IllegalArgumentException("badCode must be 16 bytes long of null, but is "
245                     + badCode.length + " + bytes long");
246         }
247         mSourceId = sourceId;
248         mSourceAddressType = sourceAddressType;
249         mSourceDevice = sourceDevice;
250         mSourceAdvertisingSid = sourceAdvertisingSid;
251         mBroadcastId = broadcastId;
252         mPaSyncState = paSyncState;
253         mBigEncryptionState = bigEncryptionState;
254         mBadCode = badCode;
255         mNumSubgroups = numSubgroups;
256         mBisSyncState = bisSyncState;
257         mSubgroupMetadata = subgroupMetadata;
258     }
259 
260     /**
261      * Get the source ID assigned by the BASS server
262      *
263      * Shall be unique for each instance of the Broadcast Receive State characteristic exposed by
264      * the server
265      *
266      * @return source ID assigned by the BASS server
267      * @hide
268      */
269     @SystemApi
getSourceId()270     public @IntRange(from = 0x00, to = 0xFF) int getSourceId() {
271         return mSourceId;
272     }
273 
274     /**
275      * Get the address type of the Broadcast Source
276      *
277      * Can be either {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC} or
278      * {@link BluetoothDevice#ADDRESS_TYPE_RANDOM
279      *
280      * @return address type of the Broadcast Source
281      * @hide
282      */
283     @SystemApi
getSourceAddressType()284     public @BluetoothDevice.AddressType int getSourceAddressType() {
285         return mSourceAddressType;
286     }
287 
288     /**
289      * Get the MAC address of the Broadcast Source, which can be Public Device Address,
290      * Random Device Address, Public Identity Address or Random (static) Identity Address
291      *
292      * @return MAC address of the Broadcast Source
293      * @hide
294      */
295     @SystemApi
getSourceDevice()296     public @NonNull BluetoothDevice getSourceDevice() {
297         return mSourceDevice;
298     }
299 
300     /**
301      * Get Advertising_SID subfield of the ADI field of the AUX_ADV_IND PDU or the
302      * LL_PERIODIC_SYNC_IND containing the SyncInfo that points to the PA transmitted by the
303      * Broadcast Source.
304      *
305      * @return 1-byte long Advertising_SID of the Broadcast Source
306      * @hide
307      */
308     @SystemApi
getSourceAdvertisingSid()309     public int getSourceAdvertisingSid() {
310         return mSourceAdvertisingSid;
311     }
312 
313     /**
314      * Broadcast_ID of the Broadcast Source
315      *
316      * @return 3-byte long Broadcast_ID of the Broadcast Source
317      * @hide
318      */
319     @SystemApi
getBroadcastId()320     public int getBroadcastId() {
321         return mBroadcastId;
322     }
323 
324     /**
325      * Get the Periodic Advertisement synchronization state between the Broadcast Sink and the
326      * Broadcast source
327      *
328      * Possible values are {@link #PA_SYNC_STATE_IDLE}, {@link #PA_SYNC_STATE_SYNCINFO_REQUEST},
329      * {@link #PA_SYNC_STATE_SYNCHRONIZED}, {@link #PA_SYNC_STATE_FAILED_TO_SYNCHRONIZE},
330      * {@link #PA_SYNC_STATE_NO_PAST}
331      *
332      * @return Periodic Advertisement synchronization state
333      * @hide
334      */
335     @SystemApi
getPaSyncState()336     public @PaSyncState int getPaSyncState() {
337         return mPaSyncState;
338     }
339 
340     /**
341      * Get the encryption state of a Broadcast Isochronous Group (BIG)
342      *
343      * Possible values are {@link #BIG_ENCRYPTION_STATE_NOT_ENCRYPTED},
344      * {@link #BIG_ENCRYPTION_STATE_CODE_REQUIRED}, {@link #BIG_ENCRYPTION_STATE_DECRYPTING},
345      * {@link #BIG_ENCRYPTION_STATE_DECRYPTING}, and {@link #BIG_ENCRYPTION_STATE_BAD_CODE}
346      *
347      * @return encryption state of a Broadcast Isochronous Group (BIG)
348      * @hide
349      */
350     @SystemApi
getBigEncryptionState()351     public @BigEncryptionState int getBigEncryptionState() {
352         return mBigEncryptionState;
353     }
354 
355     /**
356      * If {@link #getBigEncryptionState()} returns {@link #BIG_ENCRYPTION_STATE_BAD_CODE}, this
357      * method returns the value of the incorrect 16-octet Broadcast Code that fails to decrypt
358      * an audio stream from a Broadcast Source.
359      *
360      * @return 16-octet Broadcast Code, or null if {@link #getBigEncryptionState()} does not return
361      * {@link #BIG_ENCRYPTION_STATE_BAD_CODE}
362      * @hide
363      */
364     @SystemApi
getBadCode()365     public @Nullable byte[] getBadCode() {
366         return mBadCode;
367     }
368 
369     /**
370      * Get number of Broadcast subgroups being added to this sink
371      *
372      * @return number of Broadcast subgroups being added to this sink
373      */
getNumSubgroups()374     public int getNumSubgroups() {
375         return mNumSubgroups;
376     }
377 
378     /**
379      * Get a list of bitfield on whether a Broadcast Isochronous Stream (BIS) is synchronized
380      * between the sink and source
381      *
382      * The number of items in the returned list is the same as {@link #getNumSubgroups()}. For each
383      * subgroup, at most 31 BISes are available and their synchronization state is indicated by its
384      * bit value at the particular offset (i.e. Bit 0-30 = BIS_index[1-31])
385      *
386      * For example, if (BisSyncState & 0b1 << 5) != 0, BIS 5 is synchronized between source and sync
387      *
388      * There is a special case, 0xFFFFFFFF to indicate Broadcast Sink failed to synchronize to
389      * a particular subgroup
390      *
391      * @return a list of bitfield on whether a Broadcast Isochronous Stream (BIS) is synchronized
392      * between the sink and source
393      * @hide
394      */
395     @SystemApi
getBisSyncState()396     public @NonNull List<Long> getBisSyncState() {
397         return mBisSyncState;
398     }
399 
400     /**
401      * Get metadata for every subgroup added to this Broadcast Sink
402      *
403      * The number of items in the returned list is the same as {@link #getNumSubgroups()}.
404      *
405      * @return metadata for every subgroup added to this Broadcast Sink
406      * @hide
407      */
408     @SystemApi
getSubgroupMetadata()409     public @NonNull List<BluetoothLeAudioContentMetadata> getSubgroupMetadata() {
410         return mSubgroupMetadata;
411     }
412 
413     /**
414      * {@inheritDoc}
415      * @hide
416      */
417     @Override
describeContents()418     public int describeContents() {
419         return 0;
420     }
421 
422     /**
423      * {@inheritDoc}
424      * @hide
425      */
426     @Override
writeToParcel(Parcel out, int flags)427     public void writeToParcel(Parcel out, int flags) {
428         out.writeInt(mSourceId);
429         out.writeInt(mSourceAddressType);
430         out.writeTypedObject(mSourceDevice, 0);
431         out.writeInt(mSourceAdvertisingSid);
432         out.writeInt(mBroadcastId);
433         out.writeInt(mPaSyncState);
434         out.writeInt(mBigEncryptionState);
435 
436         if (mBadCode != null) {
437             out.writeInt(mBadCode.length);
438             out.writeByteArray(mBadCode);
439         } else {
440             // -1 indicates that there is no "bad broadcast code"
441             out.writeInt(-1);
442         }
443         out.writeInt(mNumSubgroups);
444         out.writeList(mBisSyncState);
445         out.writeTypedList(mSubgroupMetadata);
446     }
447 
448     /**
449      * A {@link Parcelable.Creator} to create {@link BluetoothLeBroadcastReceiveState} from parcel.
450      * @hide
451      */
452     @SystemApi
453     public static final @NonNull Parcelable.Creator<BluetoothLeBroadcastReceiveState> CREATOR =
454             new Parcelable.Creator<BluetoothLeBroadcastReceiveState>() {
455                 public @NonNull BluetoothLeBroadcastReceiveState createFromParcel(
456                         @NonNull Parcel in) {
457                     final int sourceId = in.readInt();
458                     final int sourceAddressType = in.readInt();
459                     final BluetoothDevice sourceDevice =
460                             in.readTypedObject(BluetoothDevice.CREATOR);
461                     final int sourceAdvertisingSid = in.readInt();
462                     final int broadcastId = in.readInt();
463                     final int paSyncState = in.readInt();
464                     final int bigEncryptionState = in.readInt();
465                     final int badCodeLen = in.readInt();
466                     byte[] badCode = null;
467 
468                     if (badCodeLen != -1) {
469                         badCode = new byte[badCodeLen];
470                         if (badCodeLen > 0) {
471                             in.readByteArray(badCode);
472                         }
473                     }
474                     final byte numSubGroups = in.readByte();
475                     final List<Long> bisSyncState =
476                             in.readArrayList(Long.class.getClassLoader(), Long.class);
477                     final List<BluetoothLeAudioContentMetadata> subgroupMetadata =
478                             new ArrayList<>();
479                     in.readTypedList(subgroupMetadata, BluetoothLeAudioContentMetadata.CREATOR);
480 
481                     return new BluetoothLeBroadcastReceiveState(
482                             sourceId,
483                             sourceAddressType,
484                             sourceDevice,
485                             sourceAdvertisingSid,
486                             broadcastId,
487                             paSyncState,
488                             bigEncryptionState,
489                             badCode,
490                             numSubGroups,
491                             bisSyncState,
492                             subgroupMetadata);
493                 }
494 
495                 public @NonNull BluetoothLeBroadcastReceiveState[] newArray(int size) {
496                     return new BluetoothLeBroadcastReceiveState[size];
497                 }
498             };
499 }
500