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