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