1 /*   Copyright 2019 HIMSA II K/S - www.himsa.com
2  * Represented by EHIMA - www.ehima.com
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "BluetoothLeAudioServiceJni"
18 
19 #include <hardware/bluetooth.h>
20 
21 #include <array>
22 #include <optional>
23 #include <shared_mutex>
24 
25 #include "com_android_bluetooth.h"
26 #include "hardware/bt_le_audio.h"
27 
28 using bluetooth::le_audio::BroadcastId;
29 using bluetooth::le_audio::BroadcastState;
30 using bluetooth::le_audio::btle_audio_bits_per_sample_index_t;
31 using bluetooth::le_audio::btle_audio_channel_count_index_t;
32 using bluetooth::le_audio::btle_audio_codec_config_t;
33 using bluetooth::le_audio::btle_audio_codec_index_t;
34 using bluetooth::le_audio::btle_audio_frame_duration_index_t;
35 using bluetooth::le_audio::btle_audio_sample_rate_index_t;
36 using bluetooth::le_audio::ConnectionState;
37 using bluetooth::le_audio::GroupNodeStatus;
38 using bluetooth::le_audio::GroupStatus;
39 using bluetooth::le_audio::GroupStreamStatus;
40 using bluetooth::le_audio::LeAudioBroadcasterCallbacks;
41 using bluetooth::le_audio::LeAudioBroadcasterInterface;
42 using bluetooth::le_audio::LeAudioClientCallbacks;
43 using bluetooth::le_audio::LeAudioClientInterface;
44 using bluetooth::le_audio::UnicastMonitorModeStatus;
45 
46 namespace android {
47 static jmethodID method_onInitialized;
48 static jmethodID method_onConnectionStateChanged;
49 static jmethodID method_onGroupStatus;
50 static jmethodID method_onGroupNodeStatus;
51 static jmethodID method_onAudioConf;
52 static jmethodID method_onSinkAudioLocationAvailable;
53 static jmethodID method_onAudioLocalCodecCapabilities;
54 static jmethodID method_onAudioGroupCurrentCodecConf;
55 static jmethodID method_onAudioGroupSelectableCodecConf;
56 static jmethodID method_onHealthBasedRecommendationAction;
57 static jmethodID method_onHealthBasedGroupRecommendationAction;
58 static jmethodID method_onUnicastMonitorModeStatus;
59 static jmethodID method_onGroupStreamStatus;
60 
61 static struct {
62   jclass clazz;
63   jmethodID constructor;
64   jmethodID getCodecType;
65   jmethodID getSampleRate;
66   jmethodID getBitsPerSample;
67   jmethodID getChannelCount;
68   jmethodID getFrameDuration;
69   jmethodID getOctetsPerFrame;
70   jmethodID getCodecPriority;
71 } android_bluetooth_BluetoothLeAudioCodecConfig;
72 
73 static struct {
74   jclass clazz;
75   jmethodID constructor;
76 } android_bluetooth_BluetoothLeAudioCodecConfigMetadata;
77 
78 static struct {
79   jclass clazz;
80   jmethodID constructor;
81   jmethodID add;
82 } java_util_ArrayList;
83 
84 static struct {
85   jclass clazz;
86   jmethodID constructor;
87 } android_bluetooth_BluetoothLeBroadcastChannel;
88 
89 static struct {
90   jclass clazz;
91   jmethodID constructor;
92 } android_bluetooth_BluetoothLeBroadcastSubgroup;
93 
94 static struct {
95   jclass clazz;
96   jmethodID constructor;
97 } android_bluetooth_BluetoothLeAudioContentMetadata;
98 
99 static struct {
100   jclass clazz;
101   jmethodID constructor;
102 } android_bluetooth_BluetoothLeBroadcastMetadata;
103 
104 static struct {
105   jclass clazz;
106   jmethodID constructor;
107 } android_bluetooth_BluetoothDevice;
108 
109 static LeAudioClientInterface* sLeAudioClientInterface = nullptr;
110 static std::shared_timed_mutex interface_mutex;
111 
112 static jobject mCallbacksObj = nullptr;
113 static std::shared_timed_mutex callbacks_mutex;
114 
prepareCodecConfigObj(JNIEnv * env,btle_audio_codec_config_t codecConfig)115 jobject prepareCodecConfigObj(JNIEnv* env,
116                               btle_audio_codec_config_t codecConfig) {
117   log::info(
118       "ct: {}, codec_priority: {}, sample_rate: {}, bits_per_sample: {}, "
119       "channel_count: {}, frame_duration: {}, octets_per_frame: {}",
120       codecConfig.codec_type, codecConfig.codec_priority,
121       codecConfig.sample_rate, codecConfig.bits_per_sample,
122       codecConfig.channel_count, codecConfig.frame_duration,
123       codecConfig.octets_per_frame);
124 
125   jobject codecConfigObj = env->NewObject(
126       android_bluetooth_BluetoothLeAudioCodecConfig.clazz,
127       android_bluetooth_BluetoothLeAudioCodecConfig.constructor,
128       (jint)codecConfig.codec_type, (jint)codecConfig.codec_priority,
129       (jint)codecConfig.sample_rate, (jint)codecConfig.bits_per_sample,
130       (jint)codecConfig.channel_count, (jint)codecConfig.frame_duration,
131       (jint)codecConfig.octets_per_frame, 0, 0);
132   return codecConfigObj;
133 }
134 
prepareArrayOfCodecConfigs(JNIEnv * env,std::vector<btle_audio_codec_config_t> codecConfigs)135 jobjectArray prepareArrayOfCodecConfigs(
136     JNIEnv* env, std::vector<btle_audio_codec_config_t> codecConfigs) {
137   jsize i = 0;
138   jobjectArray CodecConfigArray = env->NewObjectArray(
139       (jsize)codecConfigs.size(),
140       android_bluetooth_BluetoothLeAudioCodecConfig.clazz, nullptr);
141 
142   for (auto const& cap : codecConfigs) {
143     jobject Obj = prepareCodecConfigObj(env, cap);
144 
145     env->SetObjectArrayElement(CodecConfigArray, i++, Obj);
146     env->DeleteLocalRef(Obj);
147   }
148 
149   return CodecConfigArray;
150 }
151 
152 class LeAudioClientCallbacksImpl : public LeAudioClientCallbacks {
153  public:
154   ~LeAudioClientCallbacksImpl() = default;
155 
OnInitialized(void)156   void OnInitialized(void) override {
157     log::info("");
158     std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
159     CallbackEnv sCallbackEnv(__func__);
160     if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
161     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onInitialized);
162   }
163 
OnConnectionState(ConnectionState state,const RawAddress & bd_addr)164   void OnConnectionState(ConnectionState state,
165                          const RawAddress& bd_addr) override {
166     log::info("state:{}, addr: {}", int(state),
167               bd_addr.ToRedactedStringForLogging());
168 
169     std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
170     CallbackEnv sCallbackEnv(__func__);
171     if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
172 
173     ScopedLocalRef<jbyteArray> addr(
174         sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
175     if (!addr.get()) {
176       log::error("Failed to new jbyteArray bd addr for connection state");
177       return;
178     }
179 
180     sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
181                                      (jbyte*)&bd_addr);
182     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged,
183                                  (jint)state, addr.get());
184   }
185 
OnGroupStatus(int group_id,GroupStatus group_status)186   void OnGroupStatus(int group_id, GroupStatus group_status) override {
187     log::info("");
188 
189     std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
190     CallbackEnv sCallbackEnv(__func__);
191     if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
192 
193     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGroupStatus,
194                                  (jint)group_id, (jint)group_status);
195   }
196 
OnGroupNodeStatus(const RawAddress & bd_addr,int group_id,GroupNodeStatus node_status)197   void OnGroupNodeStatus(const RawAddress& bd_addr, int group_id,
198                          GroupNodeStatus node_status) override {
199     log::info("");
200 
201     std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
202     CallbackEnv sCallbackEnv(__func__);
203     if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
204 
205     ScopedLocalRef<jbyteArray> addr(
206         sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
207     if (!addr.get()) {
208       log::error("Failed to new jbyteArray bd addr for group status");
209       return;
210     }
211 
212     sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
213                                      (jbyte*)&bd_addr);
214     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGroupNodeStatus,
215                                  addr.get(), (jint)group_id, (jint)node_status);
216   }
217 
OnAudioConf(uint8_t direction,int group_id,uint32_t sink_audio_location,uint32_t source_audio_location,uint16_t avail_cont)218   void OnAudioConf(uint8_t direction, int group_id,
219                    uint32_t sink_audio_location, uint32_t source_audio_location,
220                    uint16_t avail_cont) override {
221     log::info("");
222 
223     std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
224     CallbackEnv sCallbackEnv(__func__);
225     if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
226 
227     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioConf,
228                                  (jint)direction, (jint)group_id,
229                                  (jint)sink_audio_location,
230                                  (jint)source_audio_location, (jint)avail_cont);
231   }
232 
OnSinkAudioLocationAvailable(const RawAddress & bd_addr,uint32_t sink_audio_location)233   void OnSinkAudioLocationAvailable(const RawAddress& bd_addr,
234                                     uint32_t sink_audio_location) override {
235     log::info("");
236 
237     std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
238     CallbackEnv sCallbackEnv(__func__);
239     if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
240 
241     ScopedLocalRef<jbyteArray> addr(
242         sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
243     if (!addr.get()) {
244       log::error("Failed to new jbyteArray bd addr for group status");
245       return;
246     }
247 
248     sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
249                                      (jbyte*)&bd_addr);
250     sCallbackEnv->CallVoidMethod(mCallbacksObj,
251                                  method_onSinkAudioLocationAvailable,
252                                  addr.get(), (jint)sink_audio_location);
253   }
254 
OnAudioLocalCodecCapabilities(std::vector<btle_audio_codec_config_t> local_input_capa_codec_conf,std::vector<btle_audio_codec_config_t> local_output_capa_codec_conf)255   void OnAudioLocalCodecCapabilities(
256       std::vector<btle_audio_codec_config_t> local_input_capa_codec_conf,
257       std::vector<btle_audio_codec_config_t> local_output_capa_codec_conf)
258       override {
259     log::info("");
260 
261     std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
262     CallbackEnv sCallbackEnv(__func__);
263     if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
264 
265     jobject localInputCapCodecConfigArray = prepareArrayOfCodecConfigs(
266         sCallbackEnv.get(), local_input_capa_codec_conf);
267 
268     jobject localOutputCapCodecConfigArray = prepareArrayOfCodecConfigs(
269         sCallbackEnv.get(), local_output_capa_codec_conf);
270 
271     sCallbackEnv->CallVoidMethod(
272         mCallbacksObj, method_onAudioLocalCodecCapabilities,
273         localInputCapCodecConfigArray, localOutputCapCodecConfigArray);
274   }
275 
OnAudioGroupCurrentCodecConf(int group_id,btle_audio_codec_config_t input_codec_conf,btle_audio_codec_config_t output_codec_conf)276   void OnAudioGroupCurrentCodecConf(
277       int group_id, btle_audio_codec_config_t input_codec_conf,
278       btle_audio_codec_config_t output_codec_conf) override {
279     log::info("");
280 
281     std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
282     CallbackEnv sCallbackEnv(__func__);
283     if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
284 
285     jobject inputCodecConfigObj =
286         prepareCodecConfigObj(sCallbackEnv.get(), input_codec_conf);
287     jobject outputCodecConfigObj =
288         prepareCodecConfigObj(sCallbackEnv.get(), output_codec_conf);
289 
290     sCallbackEnv->CallVoidMethod(
291         mCallbacksObj, method_onAudioGroupCurrentCodecConf, (jint)group_id,
292         inputCodecConfigObj, outputCodecConfigObj);
293   }
294 
OnAudioGroupSelectableCodecConf(int group_id,std::vector<btle_audio_codec_config_t> input_selectable_codec_conf,std::vector<btle_audio_codec_config_t> output_selectable_codec_conf)295   void OnAudioGroupSelectableCodecConf(
296       int group_id,
297       std::vector<btle_audio_codec_config_t> input_selectable_codec_conf,
298       std::vector<btle_audio_codec_config_t> output_selectable_codec_conf)
299       override {
300     log::info("");
301 
302     std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
303     CallbackEnv sCallbackEnv(__func__);
304     if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
305 
306     jobject inputSelectableCodecConfigArray = prepareArrayOfCodecConfigs(
307         sCallbackEnv.get(), input_selectable_codec_conf);
308     jobject outputSelectableCodecConfigArray = prepareArrayOfCodecConfigs(
309         sCallbackEnv.get(), output_selectable_codec_conf);
310 
311     sCallbackEnv->CallVoidMethod(
312         mCallbacksObj, method_onAudioGroupSelectableCodecConf, (jint)group_id,
313         inputSelectableCodecConfigArray, outputSelectableCodecConfigArray);
314   }
315 
OnHealthBasedRecommendationAction(const RawAddress & bd_addr,bluetooth::le_audio::LeAudioHealthBasedAction action)316   void OnHealthBasedRecommendationAction(
317       const RawAddress& bd_addr,
318       bluetooth::le_audio::LeAudioHealthBasedAction action) override {
319     log::info("");
320 
321     std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
322     CallbackEnv sCallbackEnv(__func__);
323     if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
324 
325     ScopedLocalRef<jbyteArray> addr(
326         sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
327     if (!addr.get()) {
328       log::error("Failed to new jbyteArray bd addr for group status");
329       return;
330     }
331 
332     sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
333                                      (jbyte*)&bd_addr);
334     sCallbackEnv->CallVoidMethod(mCallbacksObj,
335                                  method_onHealthBasedRecommendationAction,
336                                  addr.get(), (jint)action);
337   }
338 
OnHealthBasedGroupRecommendationAction(int group_id,bluetooth::le_audio::LeAudioHealthBasedAction action)339   void OnHealthBasedGroupRecommendationAction(
340       int group_id,
341       bluetooth::le_audio::LeAudioHealthBasedAction action) override {
342     log::info("");
343 
344     std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
345     CallbackEnv sCallbackEnv(__func__);
346     if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
347 
348     sCallbackEnv->CallVoidMethod(mCallbacksObj,
349                                  method_onHealthBasedGroupRecommendationAction,
350                                  (jint)group_id, (jint)action);
351   }
352 
OnUnicastMonitorModeStatus(uint8_t direction,UnicastMonitorModeStatus status)353   void OnUnicastMonitorModeStatus(uint8_t direction,
354                                   UnicastMonitorModeStatus status) override {
355     log::info("");
356 
357     std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
358     CallbackEnv sCallbackEnv(__func__);
359     if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
360 
361     sCallbackEnv->CallVoidMethod(mCallbacksObj,
362                                  method_onUnicastMonitorModeStatus,
363                                  (jint)direction, (jint)status);
364   }
365 
OnGroupStreamStatus(int group_id,GroupStreamStatus group_stream_status)366   void OnGroupStreamStatus(int group_id,
367                            GroupStreamStatus group_stream_status) override {
368     log::info("");
369 
370     std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
371     CallbackEnv sCallbackEnv(__func__);
372     if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
373 
374     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGroupStreamStatus,
375                                  (jint)group_id, (jint)group_stream_status);
376   }
377 };
378 
379 static LeAudioClientCallbacksImpl sLeAudioClientCallbacks;
380 
prepareCodecPreferences(JNIEnv * env,jobject,jobjectArray codecConfigArray)381 std::vector<btle_audio_codec_config_t> prepareCodecPreferences(
382     JNIEnv* env, jobject /* object */, jobjectArray codecConfigArray) {
383   std::vector<btle_audio_codec_config_t> codec_preferences;
384 
385   int numConfigs = env->GetArrayLength(codecConfigArray);
386   for (int i = 0; i < numConfigs; i++) {
387     jobject jcodecConfig = env->GetObjectArrayElement(codecConfigArray, i);
388     if (jcodecConfig == nullptr) continue;
389     if (!env->IsInstanceOf(
390             jcodecConfig,
391             android_bluetooth_BluetoothLeAudioCodecConfig.clazz)) {
392       log::error("Invalid BluetoothLeAudioCodecConfig instance");
393       continue;
394     }
395     jint codecType = env->CallIntMethod(
396         jcodecConfig,
397         android_bluetooth_BluetoothLeAudioCodecConfig.getCodecType);
398 
399     btle_audio_codec_config_t codec_config = {
400         .codec_type = static_cast<btle_audio_codec_index_t>(codecType)};
401 
402     codec_preferences.push_back(codec_config);
403   }
404   return codec_preferences;
405 }
406 
initNative(JNIEnv * env,jobject object,jobjectArray codecOffloadingArray)407 static void initNative(JNIEnv* env, jobject object,
408                        jobjectArray codecOffloadingArray) {
409   std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
410   std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
411 
412   const bt_interface_t* btInf = getBluetoothInterface();
413   if (btInf == nullptr) {
414     log::error("Bluetooth module is not loaded");
415     return;
416   }
417 
418   if (mCallbacksObj != nullptr) {
419     log::info("Cleaning up LeAudio callback object");
420     env->DeleteGlobalRef(mCallbacksObj);
421     mCallbacksObj = nullptr;
422   }
423 
424   if ((mCallbacksObj = env->NewGlobalRef(object)) == nullptr) {
425     log::error("Failed to allocate Global Ref for LeAudio Callbacks");
426     return;
427   }
428 
429   android_bluetooth_BluetoothLeAudioCodecConfig.clazz =
430       (jclass)env->NewGlobalRef(
431           env->FindClass("android/bluetooth/BluetoothLeAudioCodecConfig"));
432   if (android_bluetooth_BluetoothLeAudioCodecConfig.clazz == nullptr) {
433     log::error(
434         "Failed to allocate Global Ref for BluetoothLeAudioCodecConfig class");
435     return;
436   }
437 
438   sLeAudioClientInterface =
439       (LeAudioClientInterface*)btInf->get_profile_interface(
440           BT_PROFILE_LE_AUDIO_ID);
441   if (sLeAudioClientInterface == nullptr) {
442     log::error("Failed to get Bluetooth LeAudio Interface");
443     return;
444   }
445 
446   std::vector<btle_audio_codec_config_t> codec_offloading =
447       prepareCodecPreferences(env, object, codecOffloadingArray);
448 
449   sLeAudioClientInterface->Initialize(&sLeAudioClientCallbacks,
450                                       codec_offloading);
451 }
452 
cleanupNative(JNIEnv * env,jobject)453 static void cleanupNative(JNIEnv* env, jobject /* object */) {
454   std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
455   std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
456 
457   const bt_interface_t* btInf = getBluetoothInterface();
458   if (btInf == nullptr) {
459     log::error("Bluetooth module is not loaded");
460     return;
461   }
462 
463   if (sLeAudioClientInterface != nullptr) {
464     sLeAudioClientInterface->Cleanup();
465     sLeAudioClientInterface = nullptr;
466   }
467 
468   env->DeleteGlobalRef(android_bluetooth_BluetoothLeAudioCodecConfig.clazz);
469   android_bluetooth_BluetoothLeAudioCodecConfig.clazz = nullptr;
470 
471   if (mCallbacksObj != nullptr) {
472     env->DeleteGlobalRef(mCallbacksObj);
473     mCallbacksObj = nullptr;
474   }
475 }
476 
connectLeAudioNative(JNIEnv * env,jobject,jbyteArray address)477 static jboolean connectLeAudioNative(JNIEnv* env, jobject /* object */,
478                                      jbyteArray address) {
479   log::info("");
480   std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
481   if (!sLeAudioClientInterface) return JNI_FALSE;
482 
483   jbyte* addr = env->GetByteArrayElements(address, nullptr);
484   if (!addr) {
485     jniThrowIOException(env, EINVAL);
486     return JNI_FALSE;
487   }
488 
489   RawAddress* tmpraw = (RawAddress*)addr;
490   sLeAudioClientInterface->Connect(*tmpraw);
491   env->ReleaseByteArrayElements(address, addr, 0);
492   return JNI_TRUE;
493 }
494 
disconnectLeAudioNative(JNIEnv * env,jobject,jbyteArray address)495 static jboolean disconnectLeAudioNative(JNIEnv* env, jobject /* object */,
496                                         jbyteArray address) {
497   log::info("");
498   std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
499   if (!sLeAudioClientInterface) return JNI_FALSE;
500 
501   jbyte* addr = env->GetByteArrayElements(address, nullptr);
502   if (!addr) {
503     jniThrowIOException(env, EINVAL);
504     return JNI_FALSE;
505   }
506 
507   RawAddress* tmpraw = (RawAddress*)addr;
508   sLeAudioClientInterface->Disconnect(*tmpraw);
509   env->ReleaseByteArrayElements(address, addr, 0);
510   return JNI_TRUE;
511 }
512 
setEnableStateNative(JNIEnv * env,jobject,jbyteArray address,jboolean enabled)513 static jboolean setEnableStateNative(JNIEnv* env, jobject /* object */,
514                                      jbyteArray address, jboolean enabled) {
515   std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
516   jbyte* addr = env->GetByteArrayElements(address, nullptr);
517 
518   if (!sLeAudioClientInterface) {
519     log::error("Failed to get the Bluetooth LeAudio Interface");
520     return JNI_FALSE;
521   }
522 
523   if (!addr) {
524     jniThrowIOException(env, EINVAL);
525     return JNI_FALSE;
526   }
527 
528   RawAddress* tmpraw = (RawAddress*)addr;
529   sLeAudioClientInterface->SetEnableState(*tmpraw, enabled);
530   env->ReleaseByteArrayElements(address, addr, 0);
531   return JNI_TRUE;
532 }
533 
groupAddNodeNative(JNIEnv * env,jobject,jint group_id,jbyteArray address)534 static jboolean groupAddNodeNative(JNIEnv* env, jobject /* object */,
535                                    jint group_id, jbyteArray address) {
536   std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
537   jbyte* addr = env->GetByteArrayElements(address, nullptr);
538 
539   if (!sLeAudioClientInterface) {
540     log::error("Failed to get the Bluetooth LeAudio Interface");
541     return JNI_FALSE;
542   }
543 
544   if (!addr) {
545     jniThrowIOException(env, EINVAL);
546     return JNI_FALSE;
547   }
548 
549   RawAddress* tmpraw = (RawAddress*)addr;
550   sLeAudioClientInterface->GroupAddNode(group_id, *tmpraw);
551   env->ReleaseByteArrayElements(address, addr, 0);
552 
553   return JNI_TRUE;
554 }
555 
groupRemoveNodeNative(JNIEnv * env,jobject,jint group_id,jbyteArray address)556 static jboolean groupRemoveNodeNative(JNIEnv* env, jobject /* object */,
557                                       jint group_id, jbyteArray address) {
558   std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
559   if (!sLeAudioClientInterface) {
560     log::error("Failed to get the Bluetooth LeAudio Interface");
561     return JNI_FALSE;
562   }
563 
564   jbyte* addr = env->GetByteArrayElements(address, nullptr);
565   if (!addr) {
566     jniThrowIOException(env, EINVAL);
567     return JNI_FALSE;
568   }
569 
570   RawAddress* tmpraw = (RawAddress*)addr;
571   sLeAudioClientInterface->GroupRemoveNode(group_id, *tmpraw);
572   env->ReleaseByteArrayElements(address, addr, 0);
573   return JNI_TRUE;
574 }
575 
groupSetActiveNative(JNIEnv *,jobject,jint group_id)576 static void groupSetActiveNative(JNIEnv* /* env */, jobject /* object */,
577                                  jint group_id) {
578   log::info("");
579   std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
580 
581   if (!sLeAudioClientInterface) {
582     log::error("Failed to get the Bluetooth LeAudio Interface");
583     return;
584   }
585 
586   sLeAudioClientInterface->GroupSetActive(group_id);
587 }
588 
setCodecConfigPreferenceNative(JNIEnv * env,jobject,jint group_id,jobject inputCodecConfig,jobject outputCodecConfig)589 static void setCodecConfigPreferenceNative(JNIEnv* env, jobject /* object */,
590                                            jint group_id,
591                                            jobject inputCodecConfig,
592                                            jobject outputCodecConfig) {
593   std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
594 
595   if (!env->IsInstanceOf(inputCodecConfig,
596                          android_bluetooth_BluetoothLeAudioCodecConfig.clazz) ||
597       !env->IsInstanceOf(outputCodecConfig,
598                          android_bluetooth_BluetoothLeAudioCodecConfig.clazz)) {
599     log::error("Invalid BluetoothLeAudioCodecConfig instance");
600     return;
601   }
602 
603   jint inputCodecType = env->CallIntMethod(
604       inputCodecConfig,
605       android_bluetooth_BluetoothLeAudioCodecConfig.getCodecType);
606 
607   jint inputSampleRate = env->CallIntMethod(
608       inputCodecConfig,
609       android_bluetooth_BluetoothLeAudioCodecConfig.getSampleRate);
610 
611   jint inputBitsPerSample = env->CallIntMethod(
612       inputCodecConfig,
613       android_bluetooth_BluetoothLeAudioCodecConfig.getBitsPerSample);
614 
615   jint inputChannelCount = env->CallIntMethod(
616       inputCodecConfig,
617       android_bluetooth_BluetoothLeAudioCodecConfig.getChannelCount);
618 
619   jint inputFrameDuration = env->CallIntMethod(
620       inputCodecConfig,
621       android_bluetooth_BluetoothLeAudioCodecConfig.getFrameDuration);
622 
623   jint inputOctetsPerFrame = env->CallIntMethod(
624       inputCodecConfig,
625       android_bluetooth_BluetoothLeAudioCodecConfig.getOctetsPerFrame);
626 
627   jint inputCodecPriority = env->CallIntMethod(
628       inputCodecConfig,
629       android_bluetooth_BluetoothLeAudioCodecConfig.getCodecPriority);
630 
631   btle_audio_codec_config_t input_codec_config = {
632       .codec_type = static_cast<btle_audio_codec_index_t>(inputCodecType),
633       .sample_rate =
634           static_cast<btle_audio_sample_rate_index_t>(inputSampleRate),
635       .bits_per_sample =
636           static_cast<btle_audio_bits_per_sample_index_t>(inputBitsPerSample),
637       .channel_count =
638           static_cast<btle_audio_channel_count_index_t>(inputChannelCount),
639       .frame_duration =
640           static_cast<btle_audio_frame_duration_index_t>(inputFrameDuration),
641       .octets_per_frame = static_cast<uint16_t>(inputOctetsPerFrame),
642       .codec_priority = static_cast<int32_t>(inputCodecPriority),
643   };
644 
645   jint outputCodecType = env->CallIntMethod(
646       outputCodecConfig,
647       android_bluetooth_BluetoothLeAudioCodecConfig.getCodecType);
648 
649   jint outputSampleRate = env->CallIntMethod(
650       outputCodecConfig,
651       android_bluetooth_BluetoothLeAudioCodecConfig.getSampleRate);
652 
653   jint outputBitsPerSample = env->CallIntMethod(
654       outputCodecConfig,
655       android_bluetooth_BluetoothLeAudioCodecConfig.getBitsPerSample);
656 
657   jint outputChannelCount = env->CallIntMethod(
658       outputCodecConfig,
659       android_bluetooth_BluetoothLeAudioCodecConfig.getChannelCount);
660 
661   jint outputFrameDuration = env->CallIntMethod(
662       outputCodecConfig,
663       android_bluetooth_BluetoothLeAudioCodecConfig.getFrameDuration);
664 
665   jint outputOctetsPerFrame = env->CallIntMethod(
666       outputCodecConfig,
667       android_bluetooth_BluetoothLeAudioCodecConfig.getOctetsPerFrame);
668 
669   jint outputCodecPriority = env->CallIntMethod(
670       outputCodecConfig,
671       android_bluetooth_BluetoothLeAudioCodecConfig.getCodecPriority);
672 
673   btle_audio_codec_config_t output_codec_config = {
674       .codec_type = static_cast<btle_audio_codec_index_t>(outputCodecType),
675       .sample_rate =
676           static_cast<btle_audio_sample_rate_index_t>(outputSampleRate),
677       .bits_per_sample =
678           static_cast<btle_audio_bits_per_sample_index_t>(outputBitsPerSample),
679       .channel_count =
680           static_cast<btle_audio_channel_count_index_t>(outputChannelCount),
681       .frame_duration =
682           static_cast<btle_audio_frame_duration_index_t>(outputFrameDuration),
683       .octets_per_frame = static_cast<uint16_t>(outputOctetsPerFrame),
684       .codec_priority = static_cast<int32_t>(outputCodecPriority),
685   };
686 
687   sLeAudioClientInterface->SetCodecConfigPreference(
688       group_id, input_codec_config, output_codec_config);
689 }
690 
setCcidInformationNative(JNIEnv *,jobject,jint ccid,jint contextType)691 static void setCcidInformationNative(JNIEnv* /* env */, jobject /* object */,
692                                      jint ccid, jint contextType) {
693   std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
694   if (!sLeAudioClientInterface) {
695     log::error("Failed to get the Bluetooth LeAudio Interface");
696     return;
697   }
698 
699   sLeAudioClientInterface->SetCcidInformation(ccid, contextType);
700 }
701 
setInCallNative(JNIEnv *,jobject,jboolean inCall)702 static void setInCallNative(JNIEnv* /* env */, jobject /* object */,
703                             jboolean inCall) {
704   std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
705   if (!sLeAudioClientInterface) {
706     log::error("Failed to get the Bluetooth LeAudio Interface");
707     return;
708   }
709 
710   sLeAudioClientInterface->SetInCall(inCall);
711 }
712 
setUnicastMonitorModeNative(JNIEnv *,jobject,jint direction,jboolean enable)713 static void setUnicastMonitorModeNative(JNIEnv* /* env */, jobject /* object */,
714                                         jint direction, jboolean enable) {
715   std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
716   if (!sLeAudioClientInterface) {
717     log::error("Failed to get the Bluetooth LeAudio Interface");
718     return;
719   }
720 
721   sLeAudioClientInterface->SetUnicastMonitorMode(direction, enable);
722 }
723 
sendAudioProfilePreferencesNative(JNIEnv *,jint groupId,jboolean isOutputPreferenceLeAudio,jboolean isDuplexPreferenceLeAudio)724 static void sendAudioProfilePreferencesNative(
725     JNIEnv* /* env */, jint groupId, jboolean isOutputPreferenceLeAudio,
726     jboolean isDuplexPreferenceLeAudio) {
727   std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
728   if (!sLeAudioClientInterface) {
729     log::error("Failed to get the Bluetooth LeAudio Interface");
730     return;
731   }
732 
733   sLeAudioClientInterface->SendAudioProfilePreferences(
734       groupId, isOutputPreferenceLeAudio, isDuplexPreferenceLeAudio);
735 }
736 
setGroupAllowedContextMaskNative(JNIEnv *,jobject,jint groupId,jint sinkContextTypes,jint sourceContextTypes)737 static void setGroupAllowedContextMaskNative(JNIEnv* /* env */,
738                                              jobject /* object */, jint groupId,
739                                              jint sinkContextTypes,
740                                              jint sourceContextTypes) {
741   std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
742   if (!sLeAudioClientInterface) {
743     log::error("Failed to get the Bluetooth LeAudio Interface");
744     return;
745   }
746 
747   log::info("group_id: {}, sink context types: {}, source context types: {}",
748             groupId, sinkContextTypes, sourceContextTypes);
749 
750   sLeAudioClientInterface->SetGroupAllowedContextMask(groupId, sinkContextTypes,
751                                                       sourceContextTypes);
752 }
753 
754 /* Le Audio Broadcaster */
755 static jmethodID method_onBroadcastCreated;
756 static jmethodID method_onBroadcastDestroyed;
757 static jmethodID method_onBroadcastStateChanged;
758 static jmethodID method_onBroadcastMetadataChanged;
759 
760 static LeAudioBroadcasterInterface* sLeAudioBroadcasterInterface = nullptr;
761 static std::shared_timed_mutex sBroadcasterInterfaceMutex;
762 
763 static jobject sBroadcasterCallbacksObj = nullptr;
764 static std::shared_timed_mutex sBroadcasterCallbacksMutex;
765 
766 #define VEC_UINT8_TO_UINT32(vec)                                          \
767   ((vec.data()[3] << 24) + (vec.data()[2] << 16) + (vec.data()[1] << 8) + \
768    vec.data()[0])
769 
770 #define VEC_UINT8_TO_UINT16(vec) (((vec).data()[1] << 8) + ((vec).data()[0]))
771 
RawPacketSize(const std::map<uint8_t,std::vector<uint8_t>> & values)772 size_t RawPacketSize(const std::map<uint8_t, std::vector<uint8_t>>& values) {
773   size_t bytes = 0;
774   for (auto const& value : values) {
775     bytes += (/* ltv_len + ltv_type */ 2 + value.second.size());
776   }
777   return bytes;
778 }
779 
prepareRawLtvArray(JNIEnv * env,const std::map<uint8_t,std::vector<uint8_t>> & metadata)780 jbyteArray prepareRawLtvArray(
781     JNIEnv* env, const std::map<uint8_t, std::vector<uint8_t>>& metadata) {
782   auto raw_meta_size = RawPacketSize(metadata);
783 
784   jbyteArray raw_metadata = env->NewByteArray(raw_meta_size);
785   if (!raw_metadata) {
786     log::error("Failed to create new jbyteArray for raw LTV");
787     return nullptr;
788   }
789 
790   jsize offset = 0;
791   for (auto const& kv_pair : metadata) {
792     // Length
793     const jbyte ltv_sz = kv_pair.second.size() + 1;
794     env->SetByteArrayRegion(raw_metadata, offset, 1, &ltv_sz);
795     offset += 1;
796     // Type
797     env->SetByteArrayRegion(raw_metadata, offset, 1,
798                             (const jbyte*)&kv_pair.first);
799     offset += 1;
800     // Value
801     env->SetByteArrayRegion(raw_metadata, offset, kv_pair.second.size(),
802                             (const jbyte*)kv_pair.second.data());
803     offset += kv_pair.second.size();
804   }
805 
806   return raw_metadata;
807 }
808 
getAudioLocationOrDefault(const std::map<uint8_t,std::vector<uint8_t>> & metadata,jlong default_location)809 static jlong getAudioLocationOrDefault(
810     const std::map<uint8_t, std::vector<uint8_t>>& metadata,
811     jlong default_location) {
812   if (metadata.count(
813           bluetooth::le_audio::kLeAudioLtvTypeAudioChannelAllocation) == 0)
814     return default_location;
815 
816   auto& vec =
817       metadata.at(bluetooth::le_audio::kLeAudioLtvTypeAudioChannelAllocation);
818   return VEC_UINT8_TO_UINT32(vec);
819 }
820 
getSamplingFrequencyOrDefault(const std::map<uint8_t,std::vector<uint8_t>> & metadata,jint default_sampling_frequency)821 static jint getSamplingFrequencyOrDefault(
822     const std::map<uint8_t, std::vector<uint8_t>>& metadata,
823     jint default_sampling_frequency) {
824   if (metadata.count(bluetooth::le_audio::kLeAudioLtvTypeSamplingFreq) == 0)
825     return default_sampling_frequency;
826 
827   auto& vec = metadata.at(bluetooth::le_audio::kLeAudioLtvTypeSamplingFreq);
828   return (jint)(vec.data()[0]);
829 }
830 
getFrameDurationOrDefault(const std::map<uint8_t,std::vector<uint8_t>> & metadata,jint default_frame_duration)831 static jint getFrameDurationOrDefault(
832     const std::map<uint8_t, std::vector<uint8_t>>& metadata,
833     jint default_frame_duration) {
834   if (metadata.count(bluetooth::le_audio::kLeAudioLtvTypeFrameDuration) == 0)
835     return default_frame_duration;
836 
837   auto& vec = metadata.at(bluetooth::le_audio::kLeAudioLtvTypeFrameDuration);
838   return (jint)(vec.data()[0]);
839 }
840 
getOctetsPerFrameOrDefault(const std::map<uint8_t,std::vector<uint8_t>> & metadata,jint default_octets_per_frame)841 static jint getOctetsPerFrameOrDefault(
842     const std::map<uint8_t, std::vector<uint8_t>>& metadata,
843     jint default_octets_per_frame) {
844   if (metadata.count(bluetooth::le_audio::kLeAudioLtvTypeOctetsPerCodecFrame) ==
845       0)
846     return default_octets_per_frame;
847 
848   auto& vec =
849       metadata.at(bluetooth::le_audio::kLeAudioLtvTypeOctetsPerCodecFrame);
850   return VEC_UINT8_TO_UINT16(vec);
851 }
852 
prepareLeAudioCodecConfigMetadataObject(JNIEnv * env,const std::map<uint8_t,std::vector<uint8_t>> & metadata)853 jobject prepareLeAudioCodecConfigMetadataObject(
854     JNIEnv* env, const std::map<uint8_t, std::vector<uint8_t>>& metadata) {
855   jlong audio_location = getAudioLocationOrDefault(metadata, -1);
856   jint sampling_frequency = getSamplingFrequencyOrDefault(metadata, 0);
857   jint frame_duration = getFrameDurationOrDefault(metadata, -1);
858   jint octets_per_frame = getOctetsPerFrameOrDefault(metadata, 0);
859   ScopedLocalRef<jbyteArray> raw_metadata(env,
860                                           prepareRawLtvArray(env, metadata));
861   if (!raw_metadata.get()) {
862     log::error("Failed to create raw metadata jbyteArray");
863     return nullptr;
864   }
865 
866   jobject obj = env->NewObject(
867       android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz,
868       android_bluetooth_BluetoothLeAudioCodecConfigMetadata.constructor,
869       audio_location, sampling_frequency, frame_duration, octets_per_frame,
870       raw_metadata.get());
871 
872   return obj;
873 }
874 
prepareLeBroadcastChannelObject(JNIEnv * env,const bluetooth::le_audio::BasicAudioAnnouncementBisConfig & bis_config)875 jobject prepareLeBroadcastChannelObject(
876     JNIEnv* env,
877     const bluetooth::le_audio::BasicAudioAnnouncementBisConfig& bis_config) {
878   ScopedLocalRef<jobject> meta_object(
879       env, prepareLeAudioCodecConfigMetadataObject(
880                env, bis_config.codec_specific_params));
881   if (!meta_object.get()) {
882     log::error("Failed to create new metadata object for bis config");
883     return nullptr;
884   }
885 
886   jobject obj =
887       env->NewObject(android_bluetooth_BluetoothLeBroadcastChannel.clazz,
888                      android_bluetooth_BluetoothLeBroadcastChannel.constructor,
889                      false, bis_config.bis_index, meta_object.get());
890 
891   return obj;
892 }
893 
prepareLeAudioContentMetadataObject(JNIEnv * env,const std::map<uint8_t,std::vector<uint8_t>> & metadata)894 jobject prepareLeAudioContentMetadataObject(
895     JNIEnv* env, const std::map<uint8_t, std::vector<uint8_t>>& metadata) {
896   jstring program_info_str = nullptr;
897   if (metadata.count(bluetooth::le_audio::kLeAudioMetadataTypeProgramInfo)) {
898     // Convert the metadata vector to string with null terminator
899     std::string p_str(
900         (const char*)metadata
901             .at(bluetooth::le_audio::kLeAudioMetadataTypeProgramInfo)
902             .data(),
903         metadata.at(bluetooth::le_audio::kLeAudioMetadataTypeProgramInfo)
904             .size());
905 
906     program_info_str = env->NewStringUTF(p_str.c_str());
907     if (!program_info_str) {
908       log::error("Failed to create new preset name String for preset name");
909       return nullptr;
910     }
911   }
912 
913   jstring language_str = nullptr;
914   if (metadata.count(bluetooth::le_audio::kLeAudioMetadataTypeLanguage)) {
915     // Convert the metadata vector to string with null terminator
916     std::string l_str(
917         (const char*)metadata
918             .at(bluetooth::le_audio::kLeAudioMetadataTypeLanguage)
919             .data(),
920         metadata.at(bluetooth::le_audio::kLeAudioMetadataTypeLanguage).size());
921 
922     language_str = env->NewStringUTF(l_str.c_str());
923     if (!language_str) {
924       log::error("Failed to create new preset name String for language");
925       return nullptr;
926     }
927   }
928 
929   // This can be nullptr
930   ScopedLocalRef<jbyteArray> raw_metadata(env,
931                                           prepareRawLtvArray(env, metadata));
932   if (!raw_metadata.get()) {
933     log::error("Failed to create raw_metadata jbyteArray");
934     return nullptr;
935   }
936 
937   jobject obj = env->NewObject(
938       android_bluetooth_BluetoothLeAudioContentMetadata.clazz,
939       android_bluetooth_BluetoothLeAudioContentMetadata.constructor,
940       program_info_str, language_str, raw_metadata.get());
941 
942   if (program_info_str) {
943     env->DeleteLocalRef(program_info_str);
944   }
945 
946   if (language_str) {
947     env->DeleteLocalRef(language_str);
948   }
949 
950   return obj;
951 }
952 
prepareLeBroadcastChannelListObject(JNIEnv * env,const std::vector<bluetooth::le_audio::BasicAudioAnnouncementBisConfig> & bis_configs)953 jobject prepareLeBroadcastChannelListObject(
954     JNIEnv* env,
955     const std::vector<bluetooth::le_audio::BasicAudioAnnouncementBisConfig>&
956         bis_configs) {
957   jobject array = env->NewObject(java_util_ArrayList.clazz,
958                                  java_util_ArrayList.constructor);
959   if (!array) {
960     log::error("Failed to create array for subgroups");
961     return nullptr;
962   }
963 
964   for (const auto& el : bis_configs) {
965     ScopedLocalRef<jobject> channel_obj(
966         env, prepareLeBroadcastChannelObject(env, el));
967     if (!channel_obj.get()) {
968       log::error("Failed to create new channel object");
969       return nullptr;
970     }
971 
972     env->CallBooleanMethod(array, java_util_ArrayList.add, channel_obj.get());
973   }
974   return array;
975 }
976 
prepareLeBroadcastSubgroupObject(JNIEnv * env,const bluetooth::le_audio::BasicAudioAnnouncementSubgroup & subgroup)977 jobject prepareLeBroadcastSubgroupObject(
978     JNIEnv* env,
979     const bluetooth::le_audio::BasicAudioAnnouncementSubgroup& subgroup) {
980   // Serialize codec ID
981   jlong jlong_codec_id =
982       subgroup.codec_config.codec_id |
983       ((jlong)subgroup.codec_config.vendor_company_id << 16) |
984       ((jlong)subgroup.codec_config.vendor_codec_id << 32);
985 
986   ScopedLocalRef<jobject> codec_config_meta_obj(
987       env, prepareLeAudioCodecConfigMetadataObject(
988                env, subgroup.codec_config.codec_specific_params));
989   if (!codec_config_meta_obj.get()) {
990     log::error("Failed to create new codec config metadata");
991     return nullptr;
992   }
993 
994   ScopedLocalRef<jobject> content_meta_obj(
995       env, prepareLeAudioContentMetadataObject(env, subgroup.metadata));
996   if (!content_meta_obj.get()) {
997     log::error("Failed to create new codec config metadata");
998     return nullptr;
999   }
1000 
1001   ScopedLocalRef<jobject> channel_list_obj(
1002       env, prepareLeBroadcastChannelListObject(env, subgroup.bis_configs));
1003   if (!channel_list_obj.get()) {
1004     log::error("Failed to create new codec config metadata");
1005     return nullptr;
1006   }
1007 
1008   // Create the subgroup
1009   return env->NewObject(
1010       android_bluetooth_BluetoothLeBroadcastSubgroup.clazz,
1011       android_bluetooth_BluetoothLeBroadcastSubgroup.constructor,
1012       jlong_codec_id, codec_config_meta_obj.get(), content_meta_obj.get(),
1013       channel_list_obj.get());
1014 }
1015 
prepareLeBroadcastSubgroupListObject(JNIEnv * env,const std::vector<bluetooth::le_audio::BasicAudioAnnouncementSubgroup> & subgroup_configs)1016 jobject prepareLeBroadcastSubgroupListObject(
1017     JNIEnv* env,
1018     const std::vector<bluetooth::le_audio::BasicAudioAnnouncementSubgroup>&
1019         subgroup_configs) {
1020   jobject array = env->NewObject(java_util_ArrayList.clazz,
1021                                  java_util_ArrayList.constructor);
1022   if (!array) {
1023     log::error("Failed to create array for subgroups");
1024     return nullptr;
1025   }
1026 
1027   for (const auto& el : subgroup_configs) {
1028     ScopedLocalRef<jobject> subgroup_obj(
1029         env, prepareLeBroadcastSubgroupObject(env, el));
1030     if (!subgroup_obj.get()) {
1031       log::error("Failed to create new subgroup object");
1032       return nullptr;
1033     }
1034 
1035     env->CallBooleanMethod(array, java_util_ArrayList.add, subgroup_obj.get());
1036   }
1037   return array;
1038 }
1039 
prepareBluetoothDeviceObject(JNIEnv * env,const RawAddress & addr,int addr_type)1040 jobject prepareBluetoothDeviceObject(JNIEnv* env, const RawAddress& addr,
1041                                      int addr_type) {
1042   // The address string has to be uppercase or the BluetoothDevice constructor
1043   // will treat it as invalid.
1044   auto addr_str = addr.ToString();
1045   std::transform(addr_str.begin(), addr_str.end(), addr_str.begin(),
1046                  [](unsigned char c) { return std::toupper(c); });
1047 
1048   ScopedLocalRef<jstring> addr_jstr(env, env->NewStringUTF(addr_str.c_str()));
1049   if (!addr_jstr.get()) {
1050     log::error("Failed to create new preset name String for preset name");
1051     return nullptr;
1052   }
1053 
1054   return env->NewObject(android_bluetooth_BluetoothDevice.clazz,
1055                         android_bluetooth_BluetoothDevice.constructor,
1056                         addr_jstr.get(), (jint)addr_type);
1057 }
1058 
prepareBluetoothLeBroadcastMetadataObject(JNIEnv * env,const bluetooth::le_audio::BroadcastMetadata & broadcast_metadata)1059 jobject prepareBluetoothLeBroadcastMetadataObject(
1060     JNIEnv* env,
1061     const bluetooth::le_audio::BroadcastMetadata& broadcast_metadata) {
1062   ScopedLocalRef<jobject> device_obj(
1063       env, prepareBluetoothDeviceObject(env, broadcast_metadata.addr,
1064                                         broadcast_metadata.addr_type));
1065   if (!device_obj.get()) {
1066     log::error("Failed to create new BluetoothDevice");
1067     return nullptr;
1068   }
1069 
1070   ScopedLocalRef<jobject> subgroup_list_obj(
1071       env,
1072       prepareLeBroadcastSubgroupListObject(
1073           env, broadcast_metadata.basic_audio_announcement.subgroup_configs));
1074   if (!subgroup_list_obj.get()) {
1075     log::error("Failed to create new Subgroup array");
1076     return nullptr;
1077   }
1078 
1079   // Remove the ending null char bytes
1080   int nativeCodeSize = 16;
1081   if (broadcast_metadata.broadcast_code) {
1082     auto& nativeCode = broadcast_metadata.broadcast_code.value();
1083     nativeCodeSize =
1084         std::find_if(nativeCode.cbegin(), nativeCode.cend(),
1085                      [](int x) { return x == 0x00; }) -
1086         nativeCode.cbegin();
1087   }
1088 
1089   ScopedLocalRef<jbyteArray> code(env, env->NewByteArray(nativeCodeSize));
1090   if (!code.get()) {
1091     log::error("Failed to create new jbyteArray for the broadcast code");
1092     return nullptr;
1093   }
1094 
1095   if (broadcast_metadata.broadcast_code) {
1096     env->SetByteArrayRegion(
1097         code.get(), 0, nativeCodeSize,
1098         (const jbyte*)broadcast_metadata.broadcast_code->data());
1099     log::assert_that(!env->ExceptionCheck(),
1100                      "assert failed: !env->ExceptionCheck()");
1101   }
1102 
1103   ScopedLocalRef<jstring> broadcast_name(
1104       env, env->NewStringUTF(broadcast_metadata.broadcast_name.c_str()));
1105   if (!broadcast_name.get()) {
1106     log::error("Failed to create new broadcast name String");
1107     return nullptr;
1108   }
1109 
1110   jint audio_cfg_quality = 0;
1111   if (broadcast_metadata.public_announcement.features &
1112       bluetooth::le_audio::kLeAudioQualityStandard) {
1113     // Set bit 0 for AUDIO_CONFIG_QUALITY_STANDARD
1114     audio_cfg_quality |= 0x1 << bluetooth::le_audio::QUALITY_STANDARD;
1115   }
1116   if (broadcast_metadata.public_announcement.features &
1117       bluetooth::le_audio::kLeAudioQualityHigh) {
1118     // Set bit 1 for AUDIO_CONFIG_QUALITY_HIGH
1119     audio_cfg_quality |= 0x1 << bluetooth::le_audio::QUALITY_HIGH;
1120   }
1121 
1122   ScopedLocalRef<jobject> public_meta_obj(
1123       env, prepareLeAudioContentMetadataObject(
1124                env, broadcast_metadata.public_announcement.metadata));
1125   if (!public_meta_obj.get()) {
1126     log::error("Failed to create new public metadata obj");
1127     return nullptr;
1128   }
1129 
1130   return env->NewObject(
1131       android_bluetooth_BluetoothLeBroadcastMetadata.clazz,
1132       android_bluetooth_BluetoothLeBroadcastMetadata.constructor,
1133       (jint)broadcast_metadata.addr_type, device_obj.get(),
1134       (jint)broadcast_metadata.adv_sid, (jint)broadcast_metadata.broadcast_id,
1135       (jint)broadcast_metadata.pa_interval,
1136       broadcast_metadata.broadcast_code ? true : false,
1137       broadcast_metadata.is_public, broadcast_name.get(),
1138       broadcast_metadata.broadcast_code ? code.get() : nullptr,
1139       (jint)broadcast_metadata.basic_audio_announcement.presentation_delay_us,
1140       audio_cfg_quality, (jint)bluetooth::le_audio::kLeAudioSourceRssiUnknown,
1141       public_meta_obj.get(), subgroup_list_obj.get());
1142 }
1143 
1144 class LeAudioBroadcasterCallbacksImpl : public LeAudioBroadcasterCallbacks {
1145  public:
1146   ~LeAudioBroadcasterCallbacksImpl() = default;
1147 
OnBroadcastCreated(uint32_t broadcast_id,bool success)1148   void OnBroadcastCreated(uint32_t broadcast_id, bool success) override {
1149     log::info("");
1150 
1151     std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex);
1152     CallbackEnv sCallbackEnv(__func__);
1153 
1154     if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return;
1155     sCallbackEnv->CallVoidMethod(sBroadcasterCallbacksObj,
1156                                  method_onBroadcastCreated, (jint)broadcast_id,
1157                                  success ? JNI_TRUE : JNI_FALSE);
1158   }
1159 
OnBroadcastDestroyed(uint32_t broadcast_id)1160   void OnBroadcastDestroyed(uint32_t broadcast_id) override {
1161     log::info("");
1162 
1163     std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex);
1164     CallbackEnv sCallbackEnv(__func__);
1165 
1166     if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return;
1167     sCallbackEnv->CallVoidMethod(sBroadcasterCallbacksObj,
1168                                  method_onBroadcastDestroyed,
1169                                  (jint)broadcast_id);
1170   }
1171 
OnBroadcastStateChanged(uint32_t broadcast_id,BroadcastState state)1172   void OnBroadcastStateChanged(uint32_t broadcast_id,
1173                                BroadcastState state) override {
1174     log::info("");
1175 
1176     std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex);
1177     CallbackEnv sCallbackEnv(__func__);
1178 
1179     if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return;
1180     sCallbackEnv->CallVoidMethod(
1181         sBroadcasterCallbacksObj, method_onBroadcastStateChanged,
1182         (jint)broadcast_id,
1183         (jint) static_cast<std::underlying_type<BroadcastState>::type>(state));
1184   }
1185 
OnBroadcastMetadataChanged(uint32_t broadcast_id,const bluetooth::le_audio::BroadcastMetadata & broadcast_metadata)1186   void OnBroadcastMetadataChanged(uint32_t broadcast_id,
1187                                   const bluetooth::le_audio::BroadcastMetadata&
1188                                       broadcast_metadata) override {
1189     log::info("");
1190 
1191     std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex);
1192     CallbackEnv sCallbackEnv(__func__);
1193 
1194     ScopedLocalRef<jobject> metadata_obj(
1195         sCallbackEnv.get(), prepareBluetoothLeBroadcastMetadataObject(
1196                                 sCallbackEnv.get(), broadcast_metadata));
1197 
1198     if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return;
1199     sCallbackEnv->CallVoidMethod(sBroadcasterCallbacksObj,
1200                                  method_onBroadcastMetadataChanged,
1201                                  (jint)broadcast_id, metadata_obj.get());
1202   }
1203 };
1204 
1205 static LeAudioBroadcasterCallbacksImpl sLeAudioBroadcasterCallbacks;
1206 
BroadcasterInitNative(JNIEnv * env,jobject object)1207 static void BroadcasterInitNative(JNIEnv* env, jobject object) {
1208   std::unique_lock<std::shared_timed_mutex> interface_lock(
1209       sBroadcasterInterfaceMutex);
1210   std::unique_lock<std::shared_timed_mutex> callbacks_lock(
1211       sBroadcasterCallbacksMutex);
1212 
1213   const bt_interface_t* btInf = getBluetoothInterface();
1214   if (btInf == nullptr) {
1215     log::error("Bluetooth module is not loaded");
1216     return;
1217   }
1218 
1219   android_bluetooth_BluetoothDevice.clazz = (jclass)env->NewGlobalRef(
1220       env->FindClass("android/bluetooth/BluetoothDevice"));
1221   if (android_bluetooth_BluetoothDevice.clazz == nullptr) {
1222     log::error("Failed to allocate Global Ref for BluetoothDevice class");
1223     return;
1224   }
1225 
1226   java_util_ArrayList.clazz =
1227       (jclass)env->NewGlobalRef(env->FindClass("java/util/ArrayList"));
1228   if (java_util_ArrayList.clazz == nullptr) {
1229     log::error("Failed to allocate Global Ref for ArrayList class");
1230     return;
1231   }
1232 
1233   android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz =
1234       (jclass)env->NewGlobalRef(env->FindClass(
1235           "android/bluetooth/BluetoothLeAudioCodecConfigMetadata"));
1236   if (android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz == nullptr) {
1237     log::error(
1238         "Failed to allocate Global Ref for BluetoothLeAudioCodecConfigMetadata "
1239         "class");
1240     return;
1241   }
1242 
1243   android_bluetooth_BluetoothLeAudioContentMetadata.clazz =
1244       (jclass)env->NewGlobalRef(
1245           env->FindClass("android/bluetooth/BluetoothLeAudioContentMetadata"));
1246   if (android_bluetooth_BluetoothLeAudioContentMetadata.clazz == nullptr) {
1247     log::error(
1248         "Failed to allocate Global Ref for BluetoothLeAudioContentMetadata "
1249         "class");
1250     return;
1251   }
1252 
1253   android_bluetooth_BluetoothLeBroadcastSubgroup.clazz =
1254       (jclass)env->NewGlobalRef(
1255           env->FindClass("android/bluetooth/BluetoothLeBroadcastSubgroup"));
1256   if (android_bluetooth_BluetoothLeBroadcastSubgroup.clazz == nullptr) {
1257     log::error(
1258         "Failed to allocate Global Ref for BluetoothLeBroadcastSubgroup class");
1259     return;
1260   }
1261 
1262   android_bluetooth_BluetoothLeBroadcastChannel.clazz =
1263       (jclass)env->NewGlobalRef(
1264           env->FindClass("android/bluetooth/BluetoothLeBroadcastChannel"));
1265   if (android_bluetooth_BluetoothLeBroadcastChannel.clazz == nullptr) {
1266     log::error(
1267         "Failed to allocate Global Ref for BluetoothLeBroadcastChannel class");
1268     return;
1269   }
1270 
1271   android_bluetooth_BluetoothLeBroadcastMetadata.clazz =
1272       (jclass)env->NewGlobalRef(
1273           env->FindClass("android/bluetooth/BluetoothLeBroadcastMetadata"));
1274   if (android_bluetooth_BluetoothLeBroadcastMetadata.clazz == nullptr) {
1275     log::error(
1276         "Failed to allocate Global Ref for BluetoothLeBroadcastMetadata class");
1277     return;
1278   }
1279 
1280   if (sBroadcasterCallbacksObj != nullptr) {
1281     log::info("Cleaning up LeAudio Broadcaster callback object");
1282     env->DeleteGlobalRef(sBroadcasterCallbacksObj);
1283     sBroadcasterCallbacksObj = nullptr;
1284   }
1285 
1286   if ((sBroadcasterCallbacksObj = env->NewGlobalRef(object)) == nullptr) {
1287     log::error(
1288         "Failed to allocate Global Ref for LeAudio Broadcaster Callbacks");
1289     return;
1290   }
1291 
1292   sLeAudioBroadcasterInterface =
1293       (LeAudioBroadcasterInterface*)btInf->get_profile_interface(
1294           BT_PROFILE_LE_AUDIO_BROADCASTER_ID);
1295   if (sLeAudioBroadcasterInterface == nullptr) {
1296     log::error("Failed to get Bluetooth LeAudio Broadcaster Interface");
1297     return;
1298   }
1299 
1300   sLeAudioBroadcasterInterface->Initialize(&sLeAudioBroadcasterCallbacks);
1301 }
1302 
BroadcasterStopNative(JNIEnv *,jobject)1303 static void BroadcasterStopNative(JNIEnv* /* env */, jobject /* object */) {
1304   std::unique_lock<std::shared_timed_mutex> interface_lock(
1305       sBroadcasterInterfaceMutex);
1306 
1307   const bt_interface_t* btInf = getBluetoothInterface();
1308   if (btInf == nullptr) {
1309     log::error("Bluetooth module is not loaded");
1310     return;
1311   }
1312 
1313   if (sLeAudioBroadcasterInterface != nullptr)
1314     sLeAudioBroadcasterInterface->Stop();
1315 }
1316 
BroadcasterCleanupNative(JNIEnv * env,jobject)1317 static void BroadcasterCleanupNative(JNIEnv* env, jobject /* object */) {
1318   std::unique_lock<std::shared_timed_mutex> interface_lock(
1319       sBroadcasterInterfaceMutex);
1320   std::unique_lock<std::shared_timed_mutex> callbacks_lock(
1321       sBroadcasterCallbacksMutex);
1322 
1323   const bt_interface_t* btInf = getBluetoothInterface();
1324   if (btInf == nullptr) {
1325     log::error("Bluetooth module is not loaded");
1326     return;
1327   }
1328 
1329   env->DeleteGlobalRef(java_util_ArrayList.clazz);
1330   java_util_ArrayList.clazz = nullptr;
1331 
1332   env->DeleteGlobalRef(android_bluetooth_BluetoothDevice.clazz);
1333   android_bluetooth_BluetoothDevice.clazz = nullptr;
1334 
1335   env->DeleteGlobalRef(
1336       android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz);
1337   android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz = nullptr;
1338 
1339   env->DeleteGlobalRef(android_bluetooth_BluetoothLeAudioContentMetadata.clazz);
1340   android_bluetooth_BluetoothLeAudioContentMetadata.clazz = nullptr;
1341 
1342   env->DeleteGlobalRef(android_bluetooth_BluetoothLeBroadcastSubgroup.clazz);
1343   android_bluetooth_BluetoothLeBroadcastSubgroup.clazz = nullptr;
1344 
1345   env->DeleteGlobalRef(android_bluetooth_BluetoothLeBroadcastChannel.clazz);
1346   android_bluetooth_BluetoothLeBroadcastChannel.clazz = nullptr;
1347 
1348   env->DeleteGlobalRef(android_bluetooth_BluetoothLeBroadcastMetadata.clazz);
1349   android_bluetooth_BluetoothLeBroadcastMetadata.clazz = nullptr;
1350 
1351   if (sLeAudioBroadcasterInterface != nullptr) {
1352     sLeAudioBroadcasterInterface->Cleanup();
1353     sLeAudioBroadcasterInterface = nullptr;
1354   }
1355 
1356   if (sBroadcasterCallbacksObj != nullptr) {
1357     env->DeleteGlobalRef(sBroadcasterCallbacksObj);
1358     sBroadcasterCallbacksObj = nullptr;
1359   }
1360 }
1361 
convertToDataVectors(JNIEnv * env,jobjectArray dataArray)1362 std::vector<std::vector<uint8_t>> convertToDataVectors(JNIEnv* env,
1363                                                        jobjectArray dataArray) {
1364   jsize arraySize = env->GetArrayLength(dataArray);
1365   std::vector<std::vector<uint8_t>> res(arraySize);
1366 
1367   for (int i = 0; i < arraySize; ++i) {
1368     jbyteArray rowData = (jbyteArray)env->GetObjectArrayElement(dataArray, i);
1369     jsize dataSize = env->GetArrayLength(rowData);
1370     std::vector<uint8_t>& rowVector = res[i];
1371     rowVector.resize(dataSize);
1372     env->GetByteArrayRegion(rowData, 0, dataSize,
1373                             reinterpret_cast<jbyte*>(rowVector.data()));
1374     env->DeleteLocalRef(rowData);
1375   }
1376   return res;
1377 }
1378 
CreateBroadcastNative(JNIEnv * env,jobject,jboolean isPublic,jstring broadcastName,jbyteArray broadcast_code,jbyteArray publicMetadata,jintArray qualityArray,jobjectArray metadataArray)1379 static void CreateBroadcastNative(JNIEnv* env, jobject /* object */,
1380                                   jboolean isPublic, jstring broadcastName,
1381                                   jbyteArray broadcast_code,
1382                                   jbyteArray publicMetadata,
1383                                   jintArray qualityArray,
1384                                   jobjectArray metadataArray) {
1385   log::info("");
1386   std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1387   if (!sLeAudioBroadcasterInterface) return;
1388 
1389   std::array<uint8_t, 16> code_array{0};
1390   if (broadcast_code) {
1391     jsize size = env->GetArrayLength(broadcast_code);
1392     if (size > 16) {
1393       log::error("broadcast code to long");
1394       return;
1395     }
1396 
1397     // Padding with zeros on MSB positions if code is shorter than 16 octets
1398     env->GetByteArrayRegion(broadcast_code, 0, size, (jbyte*)code_array.data());
1399   }
1400 
1401   const char* broadcast_name = nullptr;
1402   if (broadcastName) {
1403     broadcast_name = env->GetStringUTFChars(broadcastName, nullptr);
1404   }
1405 
1406   jbyte* public_meta = nullptr;
1407   if (publicMetadata) {
1408     public_meta = env->GetByteArrayElements(publicMetadata, nullptr);
1409   }
1410 
1411   jint* quality_array = nullptr;
1412   if (qualityArray) {
1413     quality_array = env->GetIntArrayElements(qualityArray, nullptr);
1414   }
1415 
1416   sLeAudioBroadcasterInterface->CreateBroadcast(
1417       isPublic, broadcast_name ? broadcast_name : "",
1418       broadcast_code ? std::optional<std::array<uint8_t, 16>>(code_array)
1419                      : std::nullopt,
1420       public_meta ? std::vector<uint8_t>(
1421                         public_meta, public_meta + env->GetArrayLength(publicMetadata))
1422                   : std::vector<uint8_t>(),
1423       quality_array ? std::vector<uint8_t>(
1424                         quality_array, quality_array + env->GetArrayLength(qualityArray))
1425                   : std::vector<uint8_t>(),
1426       convertToDataVectors(env, metadataArray));
1427 
1428   if (broadcast_name) env->ReleaseStringUTFChars(broadcastName, broadcast_name);
1429   if (public_meta) env->ReleaseByteArrayElements(publicMetadata, public_meta, 0);
1430   if (quality_array) env->ReleaseIntArrayElements(qualityArray, quality_array, 0);
1431 }
1432 
UpdateMetadataNative(JNIEnv * env,jobject,jint broadcast_id,jstring broadcastName,jbyteArray publicMetadata,jobjectArray metadataArray)1433 static void UpdateMetadataNative(JNIEnv* env, jobject /* object */,
1434                                  jint broadcast_id, jstring broadcastName,
1435                                  jbyteArray publicMetadata,
1436                                  jobjectArray metadataArray) {
1437   const char* broadcast_name = nullptr;
1438   if (broadcastName) {
1439     broadcast_name = env->GetStringUTFChars(broadcastName, nullptr);
1440   }
1441 
1442   jbyte* public_meta = nullptr;
1443   if (publicMetadata) {
1444     public_meta = env->GetByteArrayElements(publicMetadata, nullptr);
1445   }
1446 
1447   sLeAudioBroadcasterInterface->UpdateMetadata(
1448       broadcast_id, broadcast_name ? broadcast_name : "",
1449       public_meta
1450           ? std::vector<uint8_t>(
1451                 public_meta, public_meta + env->GetArrayLength(publicMetadata))
1452           : std::vector<uint8_t>(),
1453       convertToDataVectors(env, metadataArray));
1454 
1455   if (broadcast_name) env->ReleaseStringUTFChars(broadcastName, broadcast_name);
1456   if (public_meta) env->ReleaseByteArrayElements(publicMetadata, public_meta, 0);
1457 }
1458 
StartBroadcastNative(JNIEnv *,jobject,jint broadcast_id)1459 static void StartBroadcastNative(JNIEnv* /* env */, jobject /* object */,
1460                                  jint broadcast_id) {
1461   log::info("");
1462   std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1463   if (!sLeAudioBroadcasterInterface) return;
1464   sLeAudioBroadcasterInterface->StartBroadcast(broadcast_id);
1465 }
1466 
StopBroadcastNative(JNIEnv *,jobject,jint broadcast_id)1467 static void StopBroadcastNative(JNIEnv* /* env */, jobject /* object */,
1468                                 jint broadcast_id) {
1469   log::info("");
1470   std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1471   if (!sLeAudioBroadcasterInterface) return;
1472   sLeAudioBroadcasterInterface->StopBroadcast(broadcast_id);
1473 }
1474 
PauseBroadcastNative(JNIEnv *,jobject,jint broadcast_id)1475 static void PauseBroadcastNative(JNIEnv* /* env */, jobject /* object */,
1476                                  jint broadcast_id) {
1477   log::info("");
1478   std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1479   if (!sLeAudioBroadcasterInterface) return;
1480   sLeAudioBroadcasterInterface->PauseBroadcast(broadcast_id);
1481 }
1482 
DestroyBroadcastNative(JNIEnv *,jobject,jint broadcast_id)1483 static void DestroyBroadcastNative(JNIEnv* /* env */, jobject /* object */,
1484                                    jint broadcast_id) {
1485   log::info("");
1486   std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1487   if (!sLeAudioBroadcasterInterface) return;
1488   sLeAudioBroadcasterInterface->DestroyBroadcast(broadcast_id);
1489 }
1490 
getBroadcastMetadataNative(JNIEnv *,jobject,jint broadcast_id)1491 static void getBroadcastMetadataNative(JNIEnv* /* env */, jobject /* object */,
1492                                        jint broadcast_id) {
1493   log::info("");
1494   std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1495   if (!sLeAudioBroadcasterInterface) return;
1496   sLeAudioBroadcasterInterface->GetBroadcastMetadata(broadcast_id);
1497 }
1498 
register_com_android_bluetooth_le_audio_broadcaster(JNIEnv * env)1499 static int register_com_android_bluetooth_le_audio_broadcaster(JNIEnv* env) {
1500   const JNINativeMethod methods[] = {
1501       {"initNative", "()V", (void*)BroadcasterInitNative},
1502       {"stopNative", "()V", (void*)BroadcasterStopNative},
1503       {"cleanupNative", "()V", (void*)BroadcasterCleanupNative},
1504       {"createBroadcastNative", "(ZLjava/lang/String;[B[B[I[[B)V",
1505        (void*)CreateBroadcastNative},
1506       {"updateMetadataNative", "(ILjava/lang/String;[B[[B)V",
1507        (void*)UpdateMetadataNative},
1508       {"startBroadcastNative", "(I)V", (void*)StartBroadcastNative},
1509       {"stopBroadcastNative", "(I)V", (void*)StopBroadcastNative},
1510       {"pauseBroadcastNative", "(I)V", (void*)PauseBroadcastNative},
1511       {"destroyBroadcastNative", "(I)V", (void*)DestroyBroadcastNative},
1512       {"getBroadcastMetadataNative", "(I)V", (void*)getBroadcastMetadataNative},
1513   };
1514 
1515   const int result = REGISTER_NATIVE_METHODS(
1516       env, "com/android/bluetooth/le_audio/LeAudioBroadcasterNativeInterface",
1517       methods);
1518   if (result != 0) {
1519     return result;
1520   }
1521 
1522   const JNIJavaMethod javaMethods[] = {
1523       {"onBroadcastCreated", "(IZ)V", &method_onBroadcastCreated},
1524       {"onBroadcastDestroyed", "(I)V", &method_onBroadcastDestroyed},
1525       {"onBroadcastStateChanged", "(II)V", &method_onBroadcastStateChanged},
1526       {"onBroadcastMetadataChanged",
1527        "(ILandroid/bluetooth/BluetoothLeBroadcastMetadata;)V",
1528        &method_onBroadcastMetadataChanged},
1529   };
1530   GET_JAVA_METHODS(
1531       env, "com/android/bluetooth/le_audio/LeAudioBroadcasterNativeInterface",
1532       javaMethods);
1533 
1534   const JNIJavaMethod javaArrayListMethods[] = {
1535       {"<init>", "()V", &java_util_ArrayList.constructor},
1536       {"add", "(Ljava/lang/Object;)Z", &java_util_ArrayList.add},
1537   };
1538   GET_JAVA_METHODS(env, "java/util/ArrayList", javaArrayListMethods);
1539 
1540   const JNIJavaMethod javaLeAudioCodecMethods[] = {
1541       {"<init>", "(JIII[B)V",
1542        &android_bluetooth_BluetoothLeAudioCodecConfigMetadata.constructor},
1543   };
1544   GET_JAVA_METHODS(env, "android/bluetooth/BluetoothLeAudioCodecConfigMetadata",
1545                    javaLeAudioCodecMethods);
1546 
1547   const JNIJavaMethod javaLeAudioContentMethods[] = {
1548       {"<init>", "(Ljava/lang/String;Ljava/lang/String;[B)V",
1549        &android_bluetooth_BluetoothLeAudioContentMetadata.constructor},
1550   };
1551   GET_JAVA_METHODS(env, "android/bluetooth/BluetoothLeAudioContentMetadata",
1552                    javaLeAudioContentMethods);
1553 
1554   const JNIJavaMethod javaLeBroadcastChannelMethods[] = {
1555       {"<init>", "(ZILandroid/bluetooth/BluetoothLeAudioCodecConfigMetadata;)V",
1556        &android_bluetooth_BluetoothLeBroadcastChannel.constructor},
1557   };
1558   GET_JAVA_METHODS(env, "android/bluetooth/BluetoothLeBroadcastChannel",
1559                    javaLeBroadcastChannelMethods);
1560 
1561   const JNIJavaMethod javaLeBroadcastSubgroupMethods[] = {
1562       {"<init>",
1563        "(JLandroid/bluetooth/BluetoothLeAudioCodecConfigMetadata;"
1564        "Landroid/bluetooth/BluetoothLeAudioContentMetadata;"
1565        "Ljava/util/List;)V",
1566        &android_bluetooth_BluetoothLeBroadcastSubgroup.constructor},
1567   };
1568   GET_JAVA_METHODS(env, "android/bluetooth/BluetoothLeBroadcastSubgroup",
1569                    javaLeBroadcastSubgroupMethods);
1570 
1571   const JNIJavaMethod javaBluetoothDevieceMethods[] = {
1572       {"<init>", "(Ljava/lang/String;I)V",
1573        &android_bluetooth_BluetoothDevice.constructor},
1574   };
1575   GET_JAVA_METHODS(env, "android/bluetooth/BluetoothDevice",
1576                    javaBluetoothDevieceMethods);
1577 
1578   const JNIJavaMethod javaLeBroadcastMetadataMethods[] = {
1579       {"<init>",
1580        "(ILandroid/bluetooth/BluetoothDevice;IIIZZLjava/lang/String;"
1581        "[BIIILandroid/bluetooth/BluetoothLeAudioContentMetadata;"
1582        "Ljava/util/List;)V",
1583        &android_bluetooth_BluetoothLeBroadcastMetadata.constructor},
1584   };
1585   GET_JAVA_METHODS(env, "android/bluetooth/BluetoothLeBroadcastMetadata",
1586                    javaLeBroadcastMetadataMethods);
1587 
1588   return 0;
1589 }
1590 
register_com_android_bluetooth_le_audio(JNIEnv * env)1591 int register_com_android_bluetooth_le_audio(JNIEnv* env) {
1592   const JNINativeMethod methods[] = {
1593       {"initNative", "([Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V",
1594        (void*)initNative},
1595       {"cleanupNative", "()V", (void*)cleanupNative},
1596       {"connectLeAudioNative", "([B)Z", (void*)connectLeAudioNative},
1597       {"disconnectLeAudioNative", "([B)Z", (void*)disconnectLeAudioNative},
1598       {"setEnableStateNative", "([BZ)Z", (void*)setEnableStateNative},
1599       {"groupAddNodeNative", "(I[B)Z", (void*)groupAddNodeNative},
1600       {"groupRemoveNodeNative", "(I[B)Z", (void*)groupRemoveNodeNative},
1601       {"groupSetActiveNative", "(I)V", (void*)groupSetActiveNative},
1602       {"setCodecConfigPreferenceNative",
1603        "(ILandroid/bluetooth/BluetoothLeAudioCodecConfig;"
1604        "Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V",
1605        (void*)setCodecConfigPreferenceNative},
1606       {"setCcidInformationNative", "(II)V", (void*)setCcidInformationNative},
1607       {"setInCallNative", "(Z)V", (void*)setInCallNative},
1608       {"setUnicastMonitorModeNative", "(IZ)V",
1609        (void*)setUnicastMonitorModeNative},
1610       {"sendAudioProfilePreferencesNative", "(IZZ)V",
1611        (void*)sendAudioProfilePreferencesNative},
1612       {"setGroupAllowedContextMaskNative", "(III)V",
1613        (void*)setGroupAllowedContextMaskNative},
1614   };
1615 
1616   const int result = REGISTER_NATIVE_METHODS(
1617       env, "com/android/bluetooth/le_audio/LeAudioNativeInterface", methods);
1618   if (result != 0) {
1619     return result;
1620   }
1621 
1622   const JNIJavaMethod javaMethods[] = {
1623       {"onGroupStatus", "(II)V", &method_onGroupStatus},
1624       {"onGroupNodeStatus", "([BII)V", &method_onGroupNodeStatus},
1625       {"onAudioConf", "(IIIII)V", &method_onAudioConf},
1626       {"onSinkAudioLocationAvailable", "([BI)V",
1627        &method_onSinkAudioLocationAvailable},
1628       {"onInitialized", "()V", &method_onInitialized},
1629       {"onConnectionStateChanged", "(I[B)V", &method_onConnectionStateChanged},
1630       {"onAudioLocalCodecCapabilities",
1631        "([Landroid/bluetooth/BluetoothLeAudioCodecConfig;"
1632        "[Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V",
1633        &method_onAudioLocalCodecCapabilities},
1634       {"onAudioGroupCurrentCodecConf",
1635        "(ILandroid/bluetooth/BluetoothLeAudioCodecConfig;"
1636        "Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V",
1637        &method_onAudioGroupCurrentCodecConf},
1638       {"onAudioGroupSelectableCodecConf",
1639        "(I[Landroid/bluetooth/BluetoothLeAudioCodecConfig;"
1640        "[Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V",
1641        &method_onAudioGroupSelectableCodecConf},
1642       {"onHealthBasedRecommendationAction", "([BI)V",
1643        &method_onHealthBasedRecommendationAction},
1644       {"onHealthBasedGroupRecommendationAction", "(II)V",
1645        &method_onHealthBasedGroupRecommendationAction},
1646       {"onUnicastMonitorModeStatus", "(II)V",
1647        &method_onUnicastMonitorModeStatus},
1648       {"onGroupStreamStatus", "(II)V", &method_onGroupStreamStatus},
1649   };
1650   GET_JAVA_METHODS(env, "com/android/bluetooth/le_audio/LeAudioNativeInterface",
1651                    javaMethods);
1652 
1653   const JNIJavaMethod javaLeAudioCodecMethods[] = {
1654       {"<init>", "(IIIIIIIII)V",
1655        &android_bluetooth_BluetoothLeAudioCodecConfig.constructor},
1656       {"getCodecType", "()I",
1657        &android_bluetooth_BluetoothLeAudioCodecConfig.getCodecType},
1658       {"getSampleRate", "()I",
1659        &android_bluetooth_BluetoothLeAudioCodecConfig.getSampleRate},
1660       {"getBitsPerSample", "()I",
1661        &android_bluetooth_BluetoothLeAudioCodecConfig.getBitsPerSample},
1662       {"getChannelCount", "()I",
1663        &android_bluetooth_BluetoothLeAudioCodecConfig.getChannelCount},
1664       {"getFrameDuration", "()I",
1665        &android_bluetooth_BluetoothLeAudioCodecConfig.getFrameDuration},
1666       {"getOctetsPerFrame", "()I",
1667        &android_bluetooth_BluetoothLeAudioCodecConfig.getOctetsPerFrame},
1668       {"getCodecPriority", "()I",
1669        &android_bluetooth_BluetoothLeAudioCodecConfig.getCodecPriority},
1670   };
1671   GET_JAVA_METHODS(env, "android/bluetooth/BluetoothLeAudioCodecConfig",
1672                    javaLeAudioCodecMethods);
1673 
1674   return register_com_android_bluetooth_le_audio_broadcaster(env);
1675 }
1676 }  // namespace android
1677