• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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