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