1 /* 2 * Copyright 2021 HIMSA II K/S - www.himsa.com. 3 * Represented by EHIMA - www.ehima.com 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.bluetooth.le_audio; 19 20 import android.bluetooth.BluetoothLeAudio; 21 import android.os.ParcelUuid; 22 import android.util.Pair; 23 24 import com.android.bluetooth.btservice.ServiceFactory; 25 26 import java.util.Collections; 27 import java.util.HashMap; 28 import java.util.Map; 29 import java.util.SortedSet; 30 import java.util.TreeSet; 31 32 /** 33 * This class keeps Content Control Ids for LE Audio profiles. 34 */ 35 public class ContentControlIdKeeper { 36 37 public static final int CCID_INVALID = 0; 38 public static final int CCID_MIN = 0x01; 39 public static final int CCID_MAX = 0xFF; 40 41 private static SortedSet<Integer> sAssignedCcidList = new TreeSet(); 42 private static HashMap<ParcelUuid, Pair<Integer, Integer>> sUserMap = new HashMap(); 43 private static ServiceFactory sServiceFactory = null; 44 45 /** 46 * Functions is used to acquire Content Control ID (Ccid). Ccid is connected 47 * with a context type and the user uuid. In most of cases user uuid is the GATT service 48 * UUID which makes use of Ccid 49 * 50 * @param userUuid user identifier (GATT service) 51 * @param contextType the context types as defined in {@link BluetoothLeAudio} 52 * @return ccid to be used in the Gatt service Ccid characteristic. 53 */ acquireCcid(ParcelUuid userUuid, int contextType)54 public static synchronized int acquireCcid(ParcelUuid userUuid, int contextType) { 55 int ccid = CCID_INVALID; 56 57 if (sAssignedCcidList.size() == 0) { 58 ccid = CCID_MIN; 59 } else if (sAssignedCcidList.last() < CCID_MAX) { 60 ccid = sAssignedCcidList.last() + 1; 61 } else if (sAssignedCcidList.first() > CCID_MIN) { 62 ccid = sAssignedCcidList.first() - 1; 63 } else { 64 int first_ccid_avail = sAssignedCcidList.first() + 1; 65 while (first_ccid_avail < CCID_MAX - 1) { 66 if (!sAssignedCcidList.contains(first_ccid_avail)) { 67 ccid = first_ccid_avail; 68 break; 69 } 70 first_ccid_avail++; 71 } 72 } 73 74 if (ccid != CCID_INVALID) { 75 sAssignedCcidList.add(ccid); 76 sUserMap.put(userUuid, new Pair(ccid, contextType)); 77 78 if (sServiceFactory == null) { 79 sServiceFactory = new ServiceFactory(); 80 } 81 /* Notify LeAudioService about new ccid */ 82 LeAudioService service = sServiceFactory.getLeAudioService(); 83 if (service != null) { 84 service.setCcidInformation(userUuid, ccid, contextType); 85 } 86 } 87 return ccid; 88 } 89 90 /** 91 * Release the acquired Ccid 92 * 93 * @param value Ccid value to release 94 */ releaseCcid(int value)95 public static synchronized void releaseCcid(int value) { 96 sAssignedCcidList.remove(value); 97 sUserMap.entrySet().removeIf(entry -> entry.getValue().first.equals(value)); 98 } 99 100 /** 101 * Get Ccid information. 102 * 103 * @return Map of acquired ccids along with the user information. 104 */ getUserCcidMap()105 public static synchronized Map<ParcelUuid, Pair<Integer, Integer>> getUserCcidMap() { 106 return Collections.unmodifiableMap(sUserMap); 107 } 108 } 109