• 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 com.android.bluetooth.bass_client;
18 
19 import static com.android.bluetooth.flags.Flags.leaudioBassScanWithInternalScanController;
20 
21 import android.bluetooth.BluetoothUtils;
22 import android.bluetooth.BluetoothUtils.TypeValueEntry;
23 import android.bluetooth.le.ScanFilter;
24 import android.bluetooth.le.ScanRecord;
25 import android.bluetooth.le.ScanResult;
26 import android.os.ParcelUuid;
27 import android.util.Log;
28 
29 import java.nio.charset.StandardCharsets;
30 import java.util.Arrays;
31 import java.util.List;
32 import java.util.Map;
33 
34 /** Bass Utility functions */
35 class BassUtils {
36     private static final String TAG = BassUtils.class.getSimpleName();
37 
containUuid(List<ScanFilter> filters, ParcelUuid uuid)38     static boolean containUuid(List<ScanFilter> filters, ParcelUuid uuid) {
39         for (ScanFilter filter : filters) {
40             if (leaudioBassScanWithInternalScanController()) {
41                 if (filter.getServiceDataUuid().equals(uuid)) {
42                     return true;
43                 }
44             } else {
45                 if (filter.getServiceUuid().equals(uuid)) {
46                     return true;
47                 }
48             }
49         }
50         return false;
51     }
52 
parseBroadcastId(byte[] broadcastIdBytes)53     static int parseBroadcastId(byte[] broadcastIdBytes) {
54         int broadcastId;
55         broadcastId = (0x00FF0000 & (broadcastIdBytes[2] << 16));
56         broadcastId |= (0x0000FF00 & (broadcastIdBytes[1] << 8));
57         broadcastId |= (0x000000FF & broadcastIdBytes[0]);
58         return broadcastId;
59     }
60 
getBroadcastId(ScanResult scanResult)61     static Integer getBroadcastId(ScanResult scanResult) {
62         if (scanResult == null) {
63             Log.e(TAG, "Null scan result");
64             return BassConstants.INVALID_BROADCAST_ID;
65         }
66 
67         return getBroadcastId(scanResult.getScanRecord());
68     }
69 
getBroadcastId(ScanRecord scanRecord)70     static Integer getBroadcastId(ScanRecord scanRecord) {
71         if (scanRecord == null) {
72             Log.e(TAG, "Null scan record");
73             return BassConstants.INVALID_BROADCAST_ID;
74         }
75 
76         Map<ParcelUuid, byte[]> listOfUuids = scanRecord.getServiceData();
77         if (listOfUuids == null) {
78             Log.e(TAG, "Null service data");
79             return BassConstants.INVALID_BROADCAST_ID;
80         }
81 
82         if (listOfUuids.containsKey(BassConstants.BAAS_UUID)) {
83             byte[] bId = listOfUuids.get(BassConstants.BAAS_UUID);
84             return BassUtils.parseBroadcastId(bId);
85         } else {
86             Log.e(TAG, "No broadcast Id in service data");
87         }
88 
89         return BassConstants.INVALID_BROADCAST_ID;
90     }
91 
getPublicBroadcastData(ScanRecord scanRecord)92     static PublicBroadcastData getPublicBroadcastData(ScanRecord scanRecord) {
93         if (scanRecord == null) {
94             Log.e(TAG, "Null scan record");
95             return null;
96         }
97 
98         Map<ParcelUuid, byte[]> listOfUuids = scanRecord.getServiceData();
99         if (listOfUuids == null) {
100             Log.e(TAG, "Null service data");
101             return null;
102         }
103 
104         if (listOfUuids.containsKey(BassConstants.PUBLIC_BROADCAST_UUID)) {
105             byte[] pbAnnouncement = listOfUuids.get(BassConstants.PUBLIC_BROADCAST_UUID);
106             return PublicBroadcastData.parsePublicBroadcastData(pbAnnouncement);
107         } else {
108             log("No public broadcast data in service data");
109         }
110 
111         return null;
112     }
113 
getBroadcastName(ScanRecord scanRecord)114     static String getBroadcastName(ScanRecord scanRecord) {
115         if (scanRecord == null) {
116             Log.e(TAG, "Null scan record");
117             return null;
118         }
119         byte[] rawBytes = scanRecord.getBytes();
120         List<TypeValueEntry> entries = BluetoothUtils.parseLengthTypeValueBytes(rawBytes);
121         if (rawBytes.length > 0 && rawBytes[0] > 0 && entries.isEmpty()) {
122             Log.e(TAG, "Invalid LTV entries in Scan record");
123             return null;
124         }
125 
126         String broadcastName = null;
127         for (TypeValueEntry entry : entries) {
128             // Only use the first value of each type
129             if (broadcastName == null && entry.getType() == BassConstants.BCAST_NAME_AD_TYPE) {
130                 byte[] bytes = entry.getValue();
131                 int len = bytes.length;
132                 if (len < BassConstants.BCAST_NAME_LEN_MIN
133                         || len > BassConstants.BCAST_NAME_LEN_MAX) {
134                     Log.e(TAG, "Invalid broadcast name length in Scan record" + len);
135                     return null;
136                 }
137                 broadcastName = new String(bytes, StandardCharsets.UTF_8);
138             }
139         }
140         return broadcastName;
141     }
142 
log(String msg)143     static void log(String msg) {
144         Log.d(TAG, msg);
145     }
146 
printByteArray(byte[] array)147     static void printByteArray(byte[] array) {
148         log("Entire byte Array as string: " + Arrays.toString(array));
149     }
150 }
151