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