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 metadata metadata buffer with TLVs 172 * @param broadcastCode optional code if broadcast should be encrypted 173 */ 174 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) createBroadcast(byte[] metadata, byte[] broadcastCode)175 public void createBroadcast(byte[] metadata, byte[] broadcastCode) { 176 createBroadcastNative(metadata, broadcastCode); 177 } 178 179 /** 180 * Update LeAudio Broadcast instance metadata. 181 * 182 * @param broadcastId broadcast instance identifier 183 * @param metadata metadata buffer with TLVs 184 */ 185 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) updateMetadata(int broadcastId, byte[] metadata)186 public void updateMetadata(int broadcastId, byte[] metadata) { 187 updateMetadataNative(broadcastId, metadata); 188 } 189 190 /** 191 * Start LeAudio Broadcast instance. 192 * 193 * @param broadcastId broadcast instance identifier 194 */ 195 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) startBroadcast(int broadcastId)196 public void startBroadcast(int broadcastId) { 197 startBroadcastNative(broadcastId); 198 } 199 200 /** 201 * Stop LeAudio Broadcast instance. 202 * 203 * @param broadcastId broadcast instance identifier 204 */ 205 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) stopBroadcast(int broadcastId)206 public void stopBroadcast(int broadcastId) { 207 stopBroadcastNative(broadcastId); 208 } 209 210 /** 211 * Pause LeAudio Broadcast instance. 212 * 213 * @param broadcastId broadcast instance identifier 214 */ 215 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) pauseBroadcast(int broadcastId)216 public void pauseBroadcast(int broadcastId) { 217 pauseBroadcastNative(broadcastId); 218 } 219 220 /** 221 * Destroy LeAudio Broadcast instance. 222 * 223 * @param broadcastId broadcast instance identifier 224 */ 225 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) destroyBroadcast(int broadcastId)226 public void destroyBroadcast(int broadcastId) { 227 destroyBroadcastNative(broadcastId); 228 } 229 230 /** 231 * Get all LeAudio Broadcast instance states. 232 */ 233 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) getBroadcastMetadata(int broadcastId)234 public void getBroadcastMetadata(int broadcastId) { 235 getBroadcastMetadataNative(broadcastId); 236 } 237 238 // Native methods that call into the JNI interface classInitNative()239 private static native void classInitNative(); initNative()240 private native void initNative(); stopNative()241 private native void stopNative(); cleanupNative()242 private native void cleanupNative(); createBroadcastNative(byte[] metadata, byte[] broadcastCode)243 private native void createBroadcastNative(byte[] metadata, byte[] broadcastCode); updateMetadataNative(int broadcastId, byte[] metadata)244 private native void updateMetadataNative(int broadcastId, byte[] metadata); startBroadcastNative(int broadcastId)245 private native void startBroadcastNative(int broadcastId); stopBroadcastNative(int broadcastId)246 private native void stopBroadcastNative(int broadcastId); pauseBroadcastNative(int broadcastId)247 private native void pauseBroadcastNative(int broadcastId); destroyBroadcastNative(int broadcastId)248 private native void destroyBroadcastNative(int broadcastId); getBroadcastMetadataNative(int broadcastId)249 private native void getBroadcastMetadataNative(int broadcastId); 250 } 251