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 /* 19 * Defines the native interface that is used by state machine/service to 20 * send or receive messages from the native stack. This file is registered 21 * for the native methods in the corresponding JNI C++ file. 22 */ 23 package com.android.bluetooth.le_audio; 24 25 import android.bluetooth.BluetoothAdapter; 26 import android.bluetooth.BluetoothDevice; 27 import android.bluetooth.BluetoothLeBroadcastMetadata; 28 import android.util.Log; 29 30 import com.android.bluetooth.Utils; 31 import com.android.internal.annotations.GuardedBy; 32 import com.android.internal.annotations.VisibleForTesting; 33 34 /** 35 * LeAudio Native Interface to/from JNI. 36 */ 37 public class LeAudioBroadcasterNativeInterface { 38 private static final String TAG = "LeAudioBroadcasterNativeInterface"; 39 private static final boolean DBG = true; 40 private BluetoothAdapter mAdapter; 41 42 @GuardedBy("INSTANCE_LOCK") 43 private static LeAudioBroadcasterNativeInterface sInstance; 44 private static final Object INSTANCE_LOCK = new Object(); 45 46 static { classInitNative()47 classInitNative(); 48 } 49 LeAudioBroadcasterNativeInterface()50 private LeAudioBroadcasterNativeInterface() { 51 mAdapter = BluetoothAdapter.getDefaultAdapter(); 52 if (mAdapter == null) { 53 Log.wtf(TAG, "No Bluetooth Adapter Available"); 54 } 55 } 56 57 /** 58 * Get singleton instance. 59 */ getInstance()60 public static LeAudioBroadcasterNativeInterface getInstance() { 61 synchronized (INSTANCE_LOCK) { 62 if (sInstance == null) { 63 sInstance = new LeAudioBroadcasterNativeInterface(); 64 } 65 return sInstance; 66 } 67 } 68 sendMessageToService(LeAudioStackEvent event)69 private void sendMessageToService(LeAudioStackEvent event) { 70 LeAudioService service = LeAudioService.getLeAudioService(); 71 if (service != null) { 72 service.messageFromNative(event); 73 } else { 74 Log.e(TAG, "Event ignored, service not available: " + event); 75 } 76 } 77 78 @VisibleForTesting getDevice(byte[] address)79 public BluetoothDevice getDevice(byte[] address) { 80 return mAdapter.getRemoteDevice(address); 81 } 82 83 // Callbacks from the native stack back into the Java framework. 84 @VisibleForTesting onBroadcastCreated(int broadcastId, boolean success)85 public void onBroadcastCreated(int broadcastId, boolean success) { 86 if (DBG) { 87 Log.d(TAG, "onBroadcastCreated: broadcastId=" + broadcastId); 88 } 89 LeAudioStackEvent event = 90 new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_CREATED); 91 92 event.valueInt1 = broadcastId; 93 event.valueBool1 = success; 94 sendMessageToService(event); 95 } 96 97 @VisibleForTesting onBroadcastDestroyed(int broadcastId)98 public void onBroadcastDestroyed(int broadcastId) { 99 if (DBG) { 100 Log.d(TAG, "onBroadcastDestroyed: broadcastId=" + broadcastId); 101 } 102 LeAudioStackEvent event = 103 new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_DESTROYED); 104 105 event.valueInt1 = broadcastId; 106 sendMessageToService(event); 107 } 108 109 @VisibleForTesting onBroadcastStateChanged(int broadcastId, int state)110 public void onBroadcastStateChanged(int broadcastId, int state) { 111 if (DBG) { 112 Log.d(TAG, "onBroadcastStateChanged: broadcastId=" + broadcastId + " state=" + state); 113 } 114 LeAudioStackEvent event = 115 new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_STATE); 116 117 /* NOTICE: This is a fake device to satisfy Audio Manager in the upper 118 * layers which needs a device instance to route audio streams to the 119 * proper module (here it's Bluetooth). Broadcast has no concept of a 120 * destination or peer device therefore this fake device was created. 121 * For now it's only important that this device is a Bluetooth device. 122 */ 123 event.device = getDevice(Utils.getBytesFromAddress("FF:FF:FF:FF:FF:FF")); 124 event.valueInt1 = broadcastId; 125 event.valueInt2 = state; 126 sendMessageToService(event); 127 } 128 129 @VisibleForTesting onBroadcastMetadataChanged(int broadcastId, BluetoothLeBroadcastMetadata metadata)130 public void onBroadcastMetadataChanged(int broadcastId, BluetoothLeBroadcastMetadata metadata) { 131 if (DBG) { 132 Log.d(TAG, "onBroadcastMetadataChanged: broadcastId=" + broadcastId); 133 } 134 LeAudioStackEvent event = 135 new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_BROADCAST_METADATA_CHANGED); 136 137 event.valueInt1 = broadcastId; 138 event.broadcastMetadata = metadata; 139 sendMessageToService(event); 140 } 141 142 /** 143 * Initializes the native interface. 144 * 145 * priorities to configure. 146 */ 147 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) init()148 public void init() { 149 initNative(); 150 } 151 152 /** 153 * Stop the Broadcast Service. 154 */ 155 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) stop()156 public void stop() { 157 stopNative(); 158 } 159 160 /** 161 * Cleanup the native interface. 162 */ 163 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) cleanup()164 public void cleanup() { 165 cleanupNative(); 166 } 167 168 /** 169 * Creates LeAudio Broadcast instance. 170 * 171 * @param isPublicBroadcast this BIG is public broadcast 172 * @param broadcastName BIG broadcast name 173 * @param broadcastCode BIG broadcast code 174 * @param publicMetadata BIG public broadcast meta data 175 * @param qualityArray BIG sub group audio quality array 176 * @param metadataArray BIG sub group metadata array 177 * 178 * qualityArray and metadataArray use the same subgroup index 179 */ 180 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) createBroadcast(boolean isPublicBroadcast, String broadcastName, byte[] broadcastCode, byte[] publicMetadata, int[] qualityArray, byte[][] metadataArray)181 public void createBroadcast(boolean isPublicBroadcast, String broadcastName, 182 byte[] broadcastCode, byte[] publicMetadata, int[] qualityArray, 183 byte[][] metadataArray) { 184 createBroadcastNative(isPublicBroadcast, broadcastName, broadcastCode, publicMetadata, 185 qualityArray, metadataArray); 186 } 187 188 /** 189 * Update LeAudio Broadcast instance metadata. 190 * 191 * @param broadcastId broadcast instance identifier 192 * @param broadcastName BIG broadcast name 193 * @param publicMetadata BIG public broadcast meta data 194 * @param metadataArray BIG sub group metadata array 195 */ 196 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) updateMetadata(int broadcastId, String broadcastName, byte[] publicMetadata, byte[][] metadataArray)197 public void updateMetadata(int broadcastId, String broadcastName, 198 byte[] publicMetadata, byte[][] metadataArray) { 199 updateMetadataNative(broadcastId, broadcastName, publicMetadata, metadataArray); 200 } 201 202 /** 203 * Start LeAudio Broadcast instance. 204 * 205 * @param broadcastId broadcast instance identifier 206 */ 207 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) startBroadcast(int broadcastId)208 public void startBroadcast(int broadcastId) { 209 startBroadcastNative(broadcastId); 210 } 211 212 /** 213 * Stop LeAudio Broadcast instance. 214 * 215 * @param broadcastId broadcast instance identifier 216 */ 217 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) stopBroadcast(int broadcastId)218 public void stopBroadcast(int broadcastId) { 219 stopBroadcastNative(broadcastId); 220 } 221 222 /** 223 * Pause LeAudio Broadcast instance. 224 * 225 * @param broadcastId broadcast instance identifier 226 */ 227 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) pauseBroadcast(int broadcastId)228 public void pauseBroadcast(int broadcastId) { 229 pauseBroadcastNative(broadcastId); 230 } 231 232 /** 233 * Destroy LeAudio Broadcast instance. 234 * 235 * @param broadcastId broadcast instance identifier 236 */ 237 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) destroyBroadcast(int broadcastId)238 public void destroyBroadcast(int broadcastId) { 239 destroyBroadcastNative(broadcastId); 240 } 241 242 /** 243 * Get all LeAudio Broadcast instance states. 244 */ 245 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) getBroadcastMetadata(int broadcastId)246 public void getBroadcastMetadata(int broadcastId) { 247 getBroadcastMetadataNative(broadcastId); 248 } 249 250 // Native methods that call into the JNI interface classInitNative()251 private static native void classInitNative(); initNative()252 private native void initNative(); stopNative()253 private native void stopNative(); cleanupNative()254 private native void cleanupNative(); createBroadcastNative(boolean isPublicBroadcast, String broadcastName, byte[] broadcastCode, byte[] publicMetadata, int[] qualityArray, byte[][] metadataArray)255 private native void createBroadcastNative(boolean isPublicBroadcast, String broadcastName, 256 byte[] broadcastCode, byte[] publicMetadata, int[] qualityArray, 257 byte[][] metadataArray); updateMetadataNative(int broadcastId, String broadcastName, byte[] publicMetadata, byte[][] metadataArray)258 private native void updateMetadataNative(int broadcastId, String broadcastName, 259 byte[] publicMetadata, byte[][] metadataArray); startBroadcastNative(int broadcastId)260 private native void startBroadcastNative(int broadcastId); stopBroadcastNative(int broadcastId)261 private native void stopBroadcastNative(int broadcastId); pauseBroadcastNative(int broadcastId)262 private native void pauseBroadcastNative(int broadcastId); destroyBroadcastNative(int broadcastId)263 private native void destroyBroadcastNative(int broadcastId); getBroadcastMetadataNative(int broadcastId)264 private native void getBroadcastMetadataNative(int broadcastId); 265 } 266