• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.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.util.ArrayList;
28 import java.util.List;
29 import java.util.Objects;
30 
31 /**
32  * This class contains the subgroup level information as defined in the BASE structure of Basic
33  * Audio profile.
34  *
35  * @hide
36  */
37 @SystemApi
38 public final class BluetoothLeBroadcastSubgroup implements Parcelable {
39     private final long mCodecId;
40     private final BluetoothLeAudioCodecConfigMetadata mCodecSpecificConfig;
41     private final BluetoothLeAudioContentMetadata mContentMetadata;
42     private final List<BluetoothLeBroadcastChannel> mChannels;
43 
BluetoothLeBroadcastSubgroup( long codecId, BluetoothLeAudioCodecConfigMetadata codecSpecificConfig, BluetoothLeAudioContentMetadata contentMetadata, List<BluetoothLeBroadcastChannel> channels)44     private BluetoothLeBroadcastSubgroup(
45             long codecId,
46             BluetoothLeAudioCodecConfigMetadata codecSpecificConfig,
47             BluetoothLeAudioContentMetadata contentMetadata,
48             List<BluetoothLeBroadcastChannel> channels) {
49         mCodecId = codecId;
50         mCodecSpecificConfig = codecSpecificConfig;
51         mContentMetadata = contentMetadata;
52         mChannels = channels;
53     }
54 
55     @Override
equals(@ullable Object o)56     public boolean equals(@Nullable Object o) {
57         if (!(o instanceof BluetoothLeBroadcastSubgroup)) {
58             return false;
59         }
60         final BluetoothLeBroadcastSubgroup other = (BluetoothLeBroadcastSubgroup) o;
61         return mCodecId == other.getCodecId()
62                 && mCodecSpecificConfig.equals(other.getCodecSpecificConfig())
63                 && mContentMetadata.equals(other.getContentMetadata())
64                 && mChannels.equals(other.getChannels());
65     }
66 
67     @Override
hashCode()68     public int hashCode() {
69         return Objects.hash(mCodecId, mCodecSpecificConfig, mContentMetadata, mChannels);
70     }
71 
72     @Override
toString()73     public String toString() {
74         return "BluetoothLeBroadcastSubgroup{"
75                 + ("codecId=" + mCodecId)
76                 + (", codecSpecificConfig=" + mCodecSpecificConfig)
77                 + (", contentMetadata=" + mContentMetadata)
78                 + (", channels=" + mChannels)
79                 + '}';
80     }
81 
82     /**
83      * Get the codec ID field as defined by the Basic Audio Profile.
84      *
85      * <p>The codec ID field has 5 octets, with - Octet 0: Coding_Format as defined in Bluetooth
86      * Assigned Numbers - Octet 1-2: Company ID as defined in Bluetooth Assigned Numbers Shall be
87      * 0x0000 if octet 0 != 0xFF - Octet 3-4: Vendor-specific codec ID Shall be 0x0000 if octet 0 !=
88      * 0xFF
89      *
90      * @return 5-byte codec ID field in Java long format
91      * @hide
92      */
93     @SystemApi
getCodecId()94     public long getCodecId() {
95         return mCodecId;
96     }
97 
98     /**
99      * Get codec specific config metadata for this subgroup.
100      *
101      * @return codec specific config metadata for this subgroup
102      * @hide
103      */
104     @SystemApi
105     @NonNull
getCodecSpecificConfig()106     public BluetoothLeAudioCodecConfigMetadata getCodecSpecificConfig() {
107         return mCodecSpecificConfig;
108     }
109 
110     /**
111      * Get content metadata for this Broadcast Source subgroup.
112      *
113      * @return content metadata for this Broadcast Source subgroup
114      * @hide
115      */
116     @SystemApi
getContentMetadata()117     public @NonNull BluetoothLeAudioContentMetadata getContentMetadata() {
118         return mContentMetadata;
119     }
120 
121     /**
122      * Indicate if Broadcast Sink should have a preferred Broadcast Channel (BIS).
123      *
124      * <p>Only used by Broadcast Assistant and Sink. Ignored by Broadcast Source
125      *
126      * @return true if Broadcast Sink has at least one preferred Broadcast Channel (BIS) as
127      *     indicated by {@link BluetoothLeBroadcastChannel#isSelected()}
128      * @hide
129      */
130     @SystemApi
hasChannelPreference()131     public boolean hasChannelPreference() {
132         return mChannels.stream().anyMatch(BluetoothLeBroadcastChannel::isSelected);
133     }
134 
135     /**
136      * Get list of Broadcast Channels included in this Broadcast subgroup.
137      *
138      * <p>Each Broadcast Channel represents a Broadcast Isochronous Stream (BIS)
139      *
140      * <p>A Broadcast subgroup should contain at least 1 Broadcast Channel
141      *
142      * @return list of Broadcast Channels included in this Broadcast subgroup
143      * @hide
144      */
145     @SystemApi
getChannels()146     public @NonNull List<BluetoothLeBroadcastChannel> getChannels() {
147         return mChannels;
148     }
149 
150     /**
151      * {@inheritDoc}
152      *
153      * @hide
154      */
155     @Override
describeContents()156     public int describeContents() {
157         return 0;
158     }
159 
160     /**
161      * {@inheritDoc}
162      *
163      * @hide
164      */
165     @Override
writeToParcel(Parcel out, int flags)166     public void writeToParcel(Parcel out, int flags) {
167         out.writeLong(mCodecId);
168         out.writeTypedObject(mCodecSpecificConfig, 0);
169         out.writeTypedObject(mContentMetadata, 0);
170         out.writeTypedList(mChannels);
171     }
172 
173     /**
174      * A {@link Parcelable.Creator} to create {@link BluetoothLeBroadcastSubgroup} from parcel.
175      *
176      * @hide
177      */
178     @SystemApi @NonNull
179     public static final Creator<BluetoothLeBroadcastSubgroup> CREATOR =
180             new Creator<>() {
181                 public @NonNull BluetoothLeBroadcastSubgroup createFromParcel(@NonNull Parcel in) {
182                     Builder builder = new Builder();
183                     builder.setCodecId(in.readLong());
184                     builder.setCodecSpecificConfig(
185                             in.readTypedObject(BluetoothLeAudioCodecConfigMetadata.CREATOR));
186                     builder.setContentMetadata(
187                             in.readTypedObject(BluetoothLeAudioContentMetadata.CREATOR));
188                     List<BluetoothLeBroadcastChannel> channels = new ArrayList<>();
189                     in.readTypedList(channels, BluetoothLeBroadcastChannel.CREATOR);
190                     for (BluetoothLeBroadcastChannel channel : channels) {
191                         builder.addChannel(channel);
192                     }
193                     return builder.build();
194                 }
195 
196                 public @NonNull BluetoothLeBroadcastSubgroup[] newArray(int size) {
197                     return new BluetoothLeBroadcastSubgroup[size];
198                 }
199             };
200 
201     private static final int UNKNOWN_VALUE_PLACEHOLDER = -1;
202 
203     /**
204      * Builder for {@link BluetoothLeBroadcastSubgroup}.
205      *
206      * @hide
207      */
208     @SystemApi
209     public static final class Builder {
210         private long mCodecId = UNKNOWN_VALUE_PLACEHOLDER;
211         private BluetoothLeAudioCodecConfigMetadata mCodecSpecificConfig = null;
212         private BluetoothLeAudioContentMetadata mContentMetadata = null;
213         private final List<BluetoothLeBroadcastChannel> mChannels = new ArrayList<>();
214 
215         /**
216          * Create an empty constructor.
217          *
218          * @hide
219          */
220         @SystemApi
Builder()221         public Builder() {}
222 
223         /**
224          * Create a builder with copies of information from original object.
225          *
226          * @param original original object
227          * @hide
228          */
229         @SystemApi
Builder(@onNull BluetoothLeBroadcastSubgroup original)230         public Builder(@NonNull BluetoothLeBroadcastSubgroup original) {
231             mCodecId = original.getCodecId();
232             mCodecSpecificConfig = original.getCodecSpecificConfig();
233             mContentMetadata = original.getContentMetadata();
234             for (BluetoothLeBroadcastChannel channel : original.getChannels()) {
235                 mChannels.add(new BluetoothLeBroadcastChannel.Builder(channel).build());
236             }
237         }
238 
239         /**
240          * Set the codec ID field as defined by the Basic Audio Profile.
241          *
242          * <p>The codec ID field has 5 octets, with - Octet 0: Coding_Format as defined in Bluetooth
243          * Assigned Numbers - Octet 1-2: Company ID as defined in Bluetooth Assigned Numbers Shall
244          * be 0x0000 if octet 0 != 0xFF - Octet 3-4: Vendor-specific codec ID Shall be 0x0000 if
245          * octet 0 != 0xFF
246          *
247          * @param codecId 5-byte codec ID field in Java long format
248          * @return this builder
249          * @hide
250          */
251         @SystemApi
setCodecId(long codecId)252         public @NonNull Builder setCodecId(long codecId) {
253             mCodecId = codecId;
254             return this;
255         }
256 
257         /**
258          * Set codec specific config metadata for this subgroup.
259          *
260          * @param codecSpecificConfig codec specific config metadata for this subgroup
261          * @throws NullPointerException if codecSpecificConfig is null
262          * @return this builder
263          * @hide
264          */
265         @SystemApi
266         @NonNull
setCodecSpecificConfig( @onNull BluetoothLeAudioCodecConfigMetadata codecSpecificConfig)267         public Builder setCodecSpecificConfig(
268                 @NonNull BluetoothLeAudioCodecConfigMetadata codecSpecificConfig) {
269             requireNonNull(codecSpecificConfig);
270             mCodecSpecificConfig = codecSpecificConfig;
271             return this;
272         }
273 
274         /**
275          * Set content metadata for this Broadcast Source subgroup.
276          *
277          * @param contentMetadata content metadata for this Broadcast Source subgroup
278          * @throws NullPointerException if contentMetadata is null
279          * @return this builder
280          * @hide
281          */
282         @SystemApi
283         @NonNull
setContentMetadata( @onNull BluetoothLeAudioContentMetadata contentMetadata)284         public Builder setContentMetadata(
285                 @NonNull BluetoothLeAudioContentMetadata contentMetadata) {
286             requireNonNull(contentMetadata);
287             mContentMetadata = contentMetadata;
288             return this;
289         }
290 
291         /**
292          * Add a Broadcast Channel to this Broadcast subgroup.
293          *
294          * <p>Each Broadcast Channel represents a Broadcast Isochronous Stream (BIS)
295          *
296          * <p>A Broadcast subgroup should contain at least 1 Broadcast Channel
297          *
298          * @param channel a Broadcast Channel to be added to this Broadcast subgroup
299          * @throws NullPointerException if channel is null
300          * @return this builder
301          * @hide
302          */
303         @SystemApi
addChannel(@onNull BluetoothLeBroadcastChannel channel)304         public @NonNull Builder addChannel(@NonNull BluetoothLeBroadcastChannel channel) {
305             requireNonNull(channel);
306             mChannels.add(channel);
307             return this;
308         }
309 
310         /**
311          * Clear channel list so that one can reset the builder after create it from an existing
312          * object.
313          *
314          * @return this builder
315          * @hide
316          */
317         @SystemApi
clearChannel()318         public @NonNull Builder clearChannel() {
319             mChannels.clear();
320             return this;
321         }
322 
323         /**
324          * Build {@link BluetoothLeBroadcastSubgroup}.
325          *
326          * @return constructed {@link BluetoothLeBroadcastSubgroup}
327          * @throws NullPointerException if {@link NonNull} items are null
328          * @throws IllegalArgumentException if the object cannot be built
329          * @hide
330          */
331         @SystemApi
build()332         public @NonNull BluetoothLeBroadcastSubgroup build() {
333             requireNonNull(mCodecSpecificConfig);
334             requireNonNull(mContentMetadata);
335             if (mChannels.isEmpty()) {
336                 throw new IllegalArgumentException("Must have at least one channel");
337             }
338             return new BluetoothLeBroadcastSubgroup(
339                     mCodecId, mCodecSpecificConfig, mContentMetadata, mChannels);
340         }
341     }
342 }
343