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