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