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