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_codec_config_t;
31 using bluetooth::le_audio::btle_audio_codec_index_t;
32 using bluetooth::le_audio::ConnectionState;
33 using bluetooth::le_audio::GroupNodeStatus;
34 using bluetooth::le_audio::GroupStatus;
35 using bluetooth::le_audio::LeAudioBroadcasterCallbacks;
36 using bluetooth::le_audio::LeAudioBroadcasterInterface;
37 using bluetooth::le_audio::LeAudioClientCallbacks;
38 using bluetooth::le_audio::LeAudioClientInterface;
39
40 namespace android {
41 static jmethodID method_onInitialized;
42 static jmethodID method_onConnectionStateChanged;
43 static jmethodID method_onGroupStatus;
44 static jmethodID method_onGroupNodeStatus;
45 static jmethodID method_onAudioConf;
46 static jmethodID method_onSinkAudioLocationAvailable;
47 static jmethodID method_onAudioLocalCodecCapabilities;
48 static jmethodID method_onAudioGroupCodecConf;
49
50 static struct {
51 jclass clazz;
52 jmethodID constructor;
53 jmethodID getCodecType;
54 } android_bluetooth_BluetoothLeAudioCodecConfig;
55
56 static struct {
57 jclass clazz;
58 jmethodID constructor;
59 } android_bluetooth_BluetoothLeAudioCodecConfigMetadata;
60
61 static struct {
62 jclass clazz;
63 jmethodID constructor;
64 jmethodID add;
65 } java_util_ArrayList;
66
67 static struct {
68 jclass clazz;
69 jmethodID constructor;
70 } android_bluetooth_BluetoothLeBroadcastChannel;
71
72 static struct {
73 jclass clazz;
74 jmethodID constructor;
75 } android_bluetooth_BluetoothLeBroadcastSubgroup;
76
77 static struct {
78 jclass clazz;
79 jmethodID constructor;
80 } android_bluetooth_BluetoothLeAudioContentMetadata;
81
82 static struct {
83 jclass clazz;
84 jmethodID constructor;
85 } android_bluetooth_BluetoothLeBroadcastMetadata;
86
87 static struct {
88 jclass clazz;
89 jmethodID constructor;
90 } android_bluetooth_BluetoothDevice;
91
92 static LeAudioClientInterface* sLeAudioClientInterface = nullptr;
93 static std::shared_timed_mutex interface_mutex;
94
95 static jobject mCallbacksObj = nullptr;
96 static std::shared_timed_mutex callbacks_mutex;
97
prepareCodecConfigObj(JNIEnv * env,btle_audio_codec_config_t codecConfig)98 jobject prepareCodecConfigObj(JNIEnv* env,
99 btle_audio_codec_config_t codecConfig) {
100 jobject codecConfigObj =
101 env->NewObject(android_bluetooth_BluetoothLeAudioCodecConfig.clazz,
102 android_bluetooth_BluetoothLeAudioCodecConfig.constructor,
103 (jint)codecConfig.codec_type, 0, 0, 0, 0, 0, 0, 0, 0);
104 return codecConfigObj;
105 }
106
prepareArrayOfCodecConfigs(JNIEnv * env,std::vector<btle_audio_codec_config_t> codecConfigs)107 jobjectArray prepareArrayOfCodecConfigs(
108 JNIEnv* env, std::vector<btle_audio_codec_config_t> codecConfigs) {
109 jsize i = 0;
110 jobjectArray CodecConfigArray = env->NewObjectArray(
111 (jsize)codecConfigs.size(),
112 android_bluetooth_BluetoothLeAudioCodecConfig.clazz, nullptr);
113
114 for (auto const& cap : codecConfigs) {
115 jobject Obj = prepareCodecConfigObj(env, cap);
116
117 env->SetObjectArrayElement(CodecConfigArray, i++, Obj);
118 env->DeleteLocalRef(Obj);
119 }
120
121 return CodecConfigArray;
122 }
123
124 class LeAudioClientCallbacksImpl : public LeAudioClientCallbacks {
125 public:
126 ~LeAudioClientCallbacksImpl() = default;
127
OnInitialized(void)128 void OnInitialized(void) override {
129 LOG(INFO) << __func__;
130 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
131 CallbackEnv sCallbackEnv(__func__);
132 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
133 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onInitialized);
134 }
135
OnConnectionState(ConnectionState state,const RawAddress & bd_addr)136 void OnConnectionState(ConnectionState state,
137 const RawAddress& bd_addr) override {
138 LOG(INFO) << __func__ << ", state:" << int(state);
139
140 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
141 CallbackEnv sCallbackEnv(__func__);
142 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
143
144 ScopedLocalRef<jbyteArray> addr(
145 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
146 if (!addr.get()) {
147 LOG(ERROR) << "Failed to new jbyteArray bd addr for connection state";
148 return;
149 }
150
151 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
152 (jbyte*)&bd_addr);
153 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged,
154 (jint)state, addr.get());
155 }
156
OnGroupStatus(int group_id,GroupStatus group_status)157 void OnGroupStatus(int group_id, GroupStatus group_status) override {
158 LOG(INFO) << __func__;
159
160 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
161 CallbackEnv sCallbackEnv(__func__);
162 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
163
164 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGroupStatus,
165 (jint)group_id, (jint)group_status);
166 }
167
OnGroupNodeStatus(const RawAddress & bd_addr,int group_id,GroupNodeStatus node_status)168 void OnGroupNodeStatus(const RawAddress& bd_addr, int group_id,
169 GroupNodeStatus node_status) override {
170 LOG(INFO) << __func__;
171
172 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
173 CallbackEnv sCallbackEnv(__func__);
174 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
175
176 ScopedLocalRef<jbyteArray> addr(
177 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
178 if (!addr.get()) {
179 LOG(ERROR) << "Failed to new jbyteArray bd addr for group status";
180 return;
181 }
182
183 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
184 (jbyte*)&bd_addr);
185 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGroupNodeStatus,
186 addr.get(), (jint)group_id, (jint)node_status);
187 }
188
OnAudioConf(uint8_t direction,int group_id,uint32_t sink_audio_location,uint32_t source_audio_location,uint16_t avail_cont)189 void OnAudioConf(uint8_t direction, int group_id,
190 uint32_t sink_audio_location, uint32_t source_audio_location,
191 uint16_t avail_cont) override {
192 LOG(INFO) << __func__;
193
194 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
195 CallbackEnv sCallbackEnv(__func__);
196 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
197
198 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioConf,
199 (jint)direction, (jint)group_id,
200 (jint)sink_audio_location,
201 (jint)source_audio_location, (jint)avail_cont);
202 }
203
OnSinkAudioLocationAvailable(const RawAddress & bd_addr,uint32_t sink_audio_location)204 void OnSinkAudioLocationAvailable(const RawAddress& bd_addr,
205 uint32_t sink_audio_location) override {
206 LOG(INFO) << __func__;
207
208 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
209 CallbackEnv sCallbackEnv(__func__);
210 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
211
212 ScopedLocalRef<jbyteArray> addr(
213 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
214 if (!addr.get()) {
215 LOG(ERROR) << "Failed to new jbyteArray bd addr for group status";
216 return;
217 }
218
219 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
220 (jbyte*)&bd_addr);
221 sCallbackEnv->CallVoidMethod(mCallbacksObj,
222 method_onSinkAudioLocationAvailable,
223 addr.get(), (jint)sink_audio_location);
224 }
225
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)226 void OnAudioLocalCodecCapabilities(
227 std::vector<btle_audio_codec_config_t> local_input_capa_codec_conf,
228 std::vector<btle_audio_codec_config_t> local_output_capa_codec_conf)
229 override {
230 LOG(INFO) << __func__;
231
232 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
233 CallbackEnv sCallbackEnv(__func__);
234 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
235
236 jobject localInputCapCodecConfigArray = prepareArrayOfCodecConfigs(
237 sCallbackEnv.get(), local_input_capa_codec_conf);
238
239 jobject localOutputCapCodecConfigArray = prepareArrayOfCodecConfigs(
240 sCallbackEnv.get(), local_output_capa_codec_conf);
241
242 sCallbackEnv->CallVoidMethod(
243 mCallbacksObj, method_onAudioLocalCodecCapabilities,
244 localInputCapCodecConfigArray, localOutputCapCodecConfigArray);
245 }
246
OnAudioGroupCodecConf(int group_id,btle_audio_codec_config_t input_codec_conf,btle_audio_codec_config_t output_codec_conf,std::vector<btle_audio_codec_config_t> input_selectable_codec_conf,std::vector<btle_audio_codec_config_t> output_selectable_codec_conf)247 void OnAudioGroupCodecConf(
248 int group_id, btle_audio_codec_config_t input_codec_conf,
249 btle_audio_codec_config_t output_codec_conf,
250 std::vector<btle_audio_codec_config_t> input_selectable_codec_conf,
251 std::vector<btle_audio_codec_config_t> output_selectable_codec_conf)
252 override {
253 LOG(INFO) << __func__;
254
255 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
256 CallbackEnv sCallbackEnv(__func__);
257 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
258
259 jobject inputCodecConfigObj =
260 prepareCodecConfigObj(sCallbackEnv.get(), input_codec_conf);
261 jobject outputCodecConfigObj =
262 prepareCodecConfigObj(sCallbackEnv.get(), input_codec_conf);
263 jobject inputSelectableCodecConfigArray = prepareArrayOfCodecConfigs(
264 sCallbackEnv.get(), input_selectable_codec_conf);
265 jobject outputSelectableCodecConfigArray = prepareArrayOfCodecConfigs(
266 sCallbackEnv.get(), output_selectable_codec_conf);
267
268 sCallbackEnv->CallVoidMethod(
269 mCallbacksObj, method_onAudioGroupCodecConf, (jint)group_id,
270 inputCodecConfigObj, outputCodecConfigObj,
271 inputSelectableCodecConfigArray, outputSelectableCodecConfigArray);
272 }
273 };
274
275 static LeAudioClientCallbacksImpl sLeAudioClientCallbacks;
276
classInitNative(JNIEnv * env,jclass clazz)277 static void classInitNative(JNIEnv* env, jclass clazz) {
278 jclass jniBluetoothLeAudioCodecConfigClass =
279 env->FindClass("android/bluetooth/BluetoothLeAudioCodecConfig");
280 android_bluetooth_BluetoothLeAudioCodecConfig.constructor = env->GetMethodID(
281 jniBluetoothLeAudioCodecConfigClass, "<init>", "(IIIIIIIII)V");
282 android_bluetooth_BluetoothLeAudioCodecConfig.getCodecType = env->GetMethodID(
283 jniBluetoothLeAudioCodecConfigClass, "getCodecType", "()I");
284
285 method_onGroupStatus = env->GetMethodID(clazz, "onGroupStatus", "(II)V");
286 method_onGroupNodeStatus =
287 env->GetMethodID(clazz, "onGroupNodeStatus", "([BII)V");
288 method_onAudioConf = env->GetMethodID(clazz, "onAudioConf", "(IIIII)V");
289 method_onSinkAudioLocationAvailable =
290 env->GetMethodID(clazz, "onSinkAudioLocationAvailable", "([BI)V");
291 method_onInitialized = env->GetMethodID(clazz, "onInitialized", "()V");
292 method_onConnectionStateChanged =
293 env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V");
294 method_onAudioLocalCodecCapabilities =
295 env->GetMethodID(clazz, "onAudioLocalCodecCapabilities",
296 "([Landroid/bluetooth/BluetoothLeAudioCodecConfig;"
297 "[Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V");
298 method_onAudioGroupCodecConf =
299 env->GetMethodID(clazz, "onAudioGroupCodecConf",
300 "(ILandroid/bluetooth/BluetoothLeAudioCodecConfig;"
301 "Landroid/bluetooth/BluetoothLeAudioCodecConfig;"
302 "[Landroid/bluetooth/BluetoothLeAudioCodecConfig;"
303 "[Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V");
304 }
305
prepareCodecPreferences(JNIEnv * env,jobject object,jobjectArray codecConfigArray)306 std::vector<btle_audio_codec_config_t> prepareCodecPreferences(
307 JNIEnv* env, jobject object, jobjectArray codecConfigArray) {
308 std::vector<btle_audio_codec_config_t> codec_preferences;
309
310 int numConfigs = env->GetArrayLength(codecConfigArray);
311 for (int i = 0; i < numConfigs; i++) {
312 jobject jcodecConfig = env->GetObjectArrayElement(codecConfigArray, i);
313 if (jcodecConfig == nullptr) continue;
314 if (!env->IsInstanceOf(
315 jcodecConfig,
316 android_bluetooth_BluetoothLeAudioCodecConfig.clazz)) {
317 ALOGE("%s: Invalid BluetoothLeAudioCodecConfig instance", __func__);
318 continue;
319 }
320 jint codecType = env->CallIntMethod(
321 jcodecConfig,
322 android_bluetooth_BluetoothLeAudioCodecConfig.getCodecType);
323
324 btle_audio_codec_config_t codec_config = {
325 .codec_type = static_cast<btle_audio_codec_index_t>(codecType)};
326
327 codec_preferences.push_back(codec_config);
328 }
329 return codec_preferences;
330 }
331
initNative(JNIEnv * env,jobject object,jobjectArray codecOffloadingArray)332 static void initNative(JNIEnv* env, jobject object,
333 jobjectArray codecOffloadingArray) {
334 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
335 std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
336
337 const bt_interface_t* btInf = getBluetoothInterface();
338 if (btInf == nullptr) {
339 LOG(ERROR) << "Bluetooth module is not loaded";
340 return;
341 }
342
343 if (mCallbacksObj != nullptr) {
344 LOG(INFO) << "Cleaning up LeAudio callback object";
345 env->DeleteGlobalRef(mCallbacksObj);
346 mCallbacksObj = nullptr;
347 }
348
349 if ((mCallbacksObj = env->NewGlobalRef(object)) == nullptr) {
350 LOG(ERROR) << "Failed to allocate Global Ref for LeAudio Callbacks";
351 return;
352 }
353
354 android_bluetooth_BluetoothLeAudioCodecConfig.clazz =
355 (jclass)env->NewGlobalRef(
356 env->FindClass("android/bluetooth/BluetoothLeAudioCodecConfig"));
357 if (android_bluetooth_BluetoothLeAudioCodecConfig.clazz == nullptr) {
358 LOG(ERROR) << "Failed to allocate Global Ref for "
359 "BluetoothLeAudioCodecConfig class";
360 return;
361 }
362
363 sLeAudioClientInterface =
364 (LeAudioClientInterface*)btInf->get_profile_interface(
365 BT_PROFILE_LE_AUDIO_ID);
366 if (sLeAudioClientInterface == nullptr) {
367 LOG(ERROR) << "Failed to get Bluetooth LeAudio Interface";
368 return;
369 }
370
371 std::vector<btle_audio_codec_config_t> codec_offloading =
372 prepareCodecPreferences(env, object, codecOffloadingArray);
373
374 sLeAudioClientInterface->Initialize(&sLeAudioClientCallbacks,
375 codec_offloading);
376 }
377
cleanupNative(JNIEnv * env,jobject object)378 static void cleanupNative(JNIEnv* env, jobject object) {
379 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
380 std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
381
382 const bt_interface_t* btInf = getBluetoothInterface();
383 if (btInf == nullptr) {
384 LOG(ERROR) << "Bluetooth module is not loaded";
385 return;
386 }
387
388 if (sLeAudioClientInterface != nullptr) {
389 sLeAudioClientInterface->Cleanup();
390 sLeAudioClientInterface = nullptr;
391 }
392
393 env->DeleteGlobalRef(android_bluetooth_BluetoothLeAudioCodecConfig.clazz);
394 android_bluetooth_BluetoothLeAudioCodecConfig.clazz = nullptr;
395
396 if (mCallbacksObj != nullptr) {
397 env->DeleteGlobalRef(mCallbacksObj);
398 mCallbacksObj = nullptr;
399 }
400 }
401
connectLeAudioNative(JNIEnv * env,jobject object,jbyteArray address)402 static jboolean connectLeAudioNative(JNIEnv* env, jobject object,
403 jbyteArray address) {
404 LOG(INFO) << __func__;
405 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
406 if (!sLeAudioClientInterface) return JNI_FALSE;
407
408 jbyte* addr = env->GetByteArrayElements(address, nullptr);
409 if (!addr) {
410 jniThrowIOException(env, EINVAL);
411 return JNI_FALSE;
412 }
413
414 RawAddress* tmpraw = (RawAddress*)addr;
415 sLeAudioClientInterface->Connect(*tmpraw);
416 env->ReleaseByteArrayElements(address, addr, 0);
417 return JNI_TRUE;
418 }
419
disconnectLeAudioNative(JNIEnv * env,jobject object,jbyteArray address)420 static jboolean disconnectLeAudioNative(JNIEnv* env, jobject object,
421 jbyteArray address) {
422 LOG(INFO) << __func__;
423 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
424 if (!sLeAudioClientInterface) return JNI_FALSE;
425
426 jbyte* addr = env->GetByteArrayElements(address, nullptr);
427 if (!addr) {
428 jniThrowIOException(env, EINVAL);
429 return JNI_FALSE;
430 }
431
432 RawAddress* tmpraw = (RawAddress*)addr;
433 sLeAudioClientInterface->Disconnect(*tmpraw);
434 env->ReleaseByteArrayElements(address, addr, 0);
435 return JNI_TRUE;
436 }
437
groupAddNodeNative(JNIEnv * env,jobject object,jint group_id,jbyteArray address)438 static jboolean groupAddNodeNative(JNIEnv* env, jobject object, jint group_id,
439 jbyteArray address) {
440 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
441 jbyte* addr = env->GetByteArrayElements(address, nullptr);
442
443 if (!sLeAudioClientInterface) {
444 LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface";
445 return JNI_FALSE;
446 }
447
448 if (!addr) {
449 jniThrowIOException(env, EINVAL);
450 return JNI_FALSE;
451 }
452
453 RawAddress* tmpraw = (RawAddress*)addr;
454 sLeAudioClientInterface->GroupAddNode(group_id, *tmpraw);
455 env->ReleaseByteArrayElements(address, addr, 0);
456
457 return JNI_TRUE;
458 }
459
groupRemoveNodeNative(JNIEnv * env,jobject object,jint group_id,jbyteArray address)460 static jboolean groupRemoveNodeNative(JNIEnv* env, jobject object,
461 jint group_id, jbyteArray address) {
462 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
463 if (!sLeAudioClientInterface) {
464 LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface";
465 return JNI_FALSE;
466 }
467
468 jbyte* addr = env->GetByteArrayElements(address, nullptr);
469 if (!addr) {
470 jniThrowIOException(env, EINVAL);
471 return JNI_FALSE;
472 }
473
474 RawAddress* tmpraw = (RawAddress*)addr;
475 sLeAudioClientInterface->GroupRemoveNode(group_id, *tmpraw);
476 env->ReleaseByteArrayElements(address, addr, 0);
477 return JNI_TRUE;
478 }
479
groupSetActiveNative(JNIEnv * env,jobject object,jint group_id)480 static void groupSetActiveNative(JNIEnv* env, jobject object, jint group_id) {
481 LOG(INFO) << __func__;
482 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
483
484 if (!sLeAudioClientInterface) {
485 LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface";
486 return;
487 }
488
489 sLeAudioClientInterface->GroupSetActive(group_id);
490 }
491
setCodecConfigPreferenceNative(JNIEnv * env,jobject object,jint group_id,jobject inputCodecConfig,jobject outputCodecConfig)492 static void setCodecConfigPreferenceNative(JNIEnv* env, jobject object,
493 jint group_id,
494 jobject inputCodecConfig,
495 jobject outputCodecConfig) {
496 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
497
498 if (!env->IsInstanceOf(inputCodecConfig,
499 android_bluetooth_BluetoothLeAudioCodecConfig.clazz) ||
500 !env->IsInstanceOf(outputCodecConfig,
501 android_bluetooth_BluetoothLeAudioCodecConfig.clazz)) {
502 ALOGE("%s: Invalid BluetoothLeAudioCodecConfig instance", __func__);
503 return;
504 }
505
506 jint inputCodecType = env->CallIntMethod(
507 inputCodecConfig,
508 android_bluetooth_BluetoothLeAudioCodecConfig.getCodecType);
509
510 btle_audio_codec_config_t input_codec_config = {
511 .codec_type = static_cast<btle_audio_codec_index_t>(inputCodecType)};
512
513 jint outputCodecType = env->CallIntMethod(
514 outputCodecConfig,
515 android_bluetooth_BluetoothLeAudioCodecConfig.getCodecType);
516
517 btle_audio_codec_config_t output_codec_config = {
518 .codec_type = static_cast<btle_audio_codec_index_t>(outputCodecType)};
519
520 sLeAudioClientInterface->SetCodecConfigPreference(
521 group_id, input_codec_config, output_codec_config);
522 }
523
setCcidInformationNative(JNIEnv * env,jobject object,jint ccid,jint contextType)524 static void setCcidInformationNative(JNIEnv* env, jobject object, jint ccid,
525 jint contextType) {
526 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
527 if (!sLeAudioClientInterface) {
528 LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface";
529 return;
530 }
531
532 sLeAudioClientInterface->SetCcidInformation(ccid, contextType);
533 }
534
setInCallNative(JNIEnv * env,jobject object,jboolean inCall)535 static void setInCallNative(JNIEnv* env, jobject object, jboolean inCall) {
536 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
537 if (!sLeAudioClientInterface) {
538 LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface";
539 return;
540 }
541
542 sLeAudioClientInterface->SetInCall(inCall);
543 }
544
545 static JNINativeMethod sMethods[] = {
546 {"classInitNative", "()V", (void*)classInitNative},
547 {"initNative", "([Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V",
548 (void*)initNative},
549 {"cleanupNative", "()V", (void*)cleanupNative},
550 {"connectLeAudioNative", "([B)Z", (void*)connectLeAudioNative},
551 {"disconnectLeAudioNative", "([B)Z", (void*)disconnectLeAudioNative},
552 {"groupAddNodeNative", "(I[B)Z", (void*)groupAddNodeNative},
553 {"groupRemoveNodeNative", "(I[B)Z", (void*)groupRemoveNodeNative},
554 {"groupSetActiveNative", "(I)V", (void*)groupSetActiveNative},
555 {"setCodecConfigPreferenceNative",
556 "(ILandroid/bluetooth/BluetoothLeAudioCodecConfig;Landroid/bluetooth/"
557 "BluetoothLeAudioCodecConfig;)V",
558 (void*)setCodecConfigPreferenceNative},
559 {"setCcidInformationNative", "(II)V", (void*)setCcidInformationNative},
560 {"setInCallNative", "(Z)V", (void*)setInCallNative},
561 };
562
563 /* Le Audio Broadcaster */
564 static jmethodID method_onBroadcastCreated;
565 static jmethodID method_onBroadcastDestroyed;
566 static jmethodID method_onBroadcastStateChanged;
567 static jmethodID method_onBroadcastMetadataChanged;
568
569 static LeAudioBroadcasterInterface* sLeAudioBroadcasterInterface = nullptr;
570 static std::shared_timed_mutex sBroadcasterInterfaceMutex;
571
572 static jobject sBroadcasterCallbacksObj = nullptr;
573 static std::shared_timed_mutex sBroadcasterCallbacksMutex;
574
575 #define VEC_UINT8_TO_UINT32(vec) \
576 ((vec.data()[3] << 24) + (vec.data()[2] << 16) + (vec.data()[1] << 8) + \
577 vec.data()[0])
578
RawPacketSize(const std::map<uint8_t,std::vector<uint8_t>> & values)579 size_t RawPacketSize(const std::map<uint8_t, std::vector<uint8_t>>& values) {
580 size_t bytes = 0;
581 for (auto const& value : values) {
582 bytes += (/* ltv_len + ltv_type */ 2 + value.second.size());
583 }
584 return bytes;
585 }
586
prepareRawLtvArray(JNIEnv * env,const std::map<uint8_t,std::vector<uint8_t>> & metadata)587 jbyteArray prepareRawLtvArray(
588 JNIEnv* env, const std::map<uint8_t, std::vector<uint8_t>>& metadata) {
589 auto raw_meta_size = RawPacketSize(metadata);
590
591 jbyteArray raw_metadata = env->NewByteArray(raw_meta_size);
592 if (!raw_metadata) {
593 LOG(ERROR) << "Failed to create new jbyteArray for raw LTV";
594 return nullptr;
595 }
596
597 jsize offset = 0;
598 for (auto const& kv_pair : metadata) {
599 // Length
600 const jbyte ltv_sz = kv_pair.second.size() + 1;
601 env->SetByteArrayRegion(raw_metadata, offset, 1, <v_sz);
602 offset += 1;
603 // Type
604 env->SetByteArrayRegion(raw_metadata, offset, 1,
605 (const jbyte*)&kv_pair.first);
606 offset += 1;
607 // Value
608 env->SetByteArrayRegion(raw_metadata, offset, kv_pair.second.size(),
609 (const jbyte*)kv_pair.second.data());
610 offset += kv_pair.second.size();
611 }
612
613 return raw_metadata;
614 }
615
getAudioLocationOrDefault(const std::map<uint8_t,std::vector<uint8_t>> & metadata,jlong default_location)616 static jlong getAudioLocationOrDefault(
617 const std::map<uint8_t, std::vector<uint8_t>>& metadata,
618 jlong default_location) {
619 if (metadata.count(
620 bluetooth::le_audio::kLeAudioCodecLC3TypeAudioChannelAllocation) == 0)
621 return default_location;
622
623 auto& vec = metadata.at(
624 bluetooth::le_audio::kLeAudioCodecLC3TypeAudioChannelAllocation);
625 return VEC_UINT8_TO_UINT32(vec);
626 }
627
prepareLeAudioCodecConfigMetadataObject(JNIEnv * env,const std::map<uint8_t,std::vector<uint8_t>> & metadata)628 jobject prepareLeAudioCodecConfigMetadataObject(
629 JNIEnv* env, const std::map<uint8_t, std::vector<uint8_t>>& metadata) {
630 jlong audio_location = getAudioLocationOrDefault(metadata, -1);
631 ScopedLocalRef<jbyteArray> raw_metadata(env,
632 prepareRawLtvArray(env, metadata));
633 if (!raw_metadata.get()) {
634 LOG(ERROR) << "Failed to create raw metadata jbyteArray";
635 return nullptr;
636 }
637
638 jobject obj = env->NewObject(
639 android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz,
640 android_bluetooth_BluetoothLeAudioCodecConfigMetadata.constructor,
641 audio_location, raw_metadata.get());
642
643 return obj;
644 }
645
prepareLeBroadcastChannelObject(JNIEnv * env,const bluetooth::le_audio::BasicAudioAnnouncementBisConfig & bis_config)646 jobject prepareLeBroadcastChannelObject(
647 JNIEnv* env,
648 const bluetooth::le_audio::BasicAudioAnnouncementBisConfig& bis_config) {
649 ScopedLocalRef<jobject> meta_object(
650 env, prepareLeAudioCodecConfigMetadataObject(
651 env, bis_config.codec_specific_params));
652 if (!meta_object.get()) {
653 LOG(ERROR) << "Failed to create new metadata object for bis config";
654 return nullptr;
655 }
656
657 jobject obj =
658 env->NewObject(android_bluetooth_BluetoothLeBroadcastChannel.clazz,
659 android_bluetooth_BluetoothLeBroadcastChannel.constructor,
660 false, bis_config.bis_index, meta_object.get());
661
662 return obj;
663 }
664
prepareLeAudioContentMetadataObject(JNIEnv * env,const std::map<uint8_t,std::vector<uint8_t>> & metadata)665 jobject prepareLeAudioContentMetadataObject(
666 JNIEnv* env, const std::map<uint8_t, std::vector<uint8_t>>& metadata) {
667 jstring program_info_str = nullptr;
668 if (metadata.count(bluetooth::le_audio::kLeAudioMetadataTypeProgramInfo)) {
669 program_info_str = env->NewStringUTF(
670 (const char*)(metadata
671 .at(bluetooth::le_audio::
672 kLeAudioMetadataTypeProgramInfo)
673 .data()));
674 if (!program_info_str) {
675 LOG(ERROR) << "Failed to create new preset name String for preset name";
676 return nullptr;
677 }
678 }
679
680 jstring language_str = nullptr;
681 if (metadata.count(bluetooth::le_audio::kLeAudioMetadataTypeLanguage)) {
682 language_str = env->NewStringUTF(
683 (const char*)(metadata
684 .at(bluetooth::le_audio::kLeAudioMetadataTypeLanguage)
685 .data()));
686 if (!language_str) {
687 LOG(ERROR) << "Failed to create new preset name String for language";
688 return nullptr;
689 }
690 }
691
692 // This can be nullptr
693 ScopedLocalRef<jbyteArray> raw_metadata(env,
694 prepareRawLtvArray(env, metadata));
695 if (!raw_metadata.get()) {
696 LOG(ERROR) << "Failed to create raw_metadata jbyteArray";
697 return nullptr;
698 }
699
700 jobject obj = env->NewObject(
701 android_bluetooth_BluetoothLeAudioContentMetadata.clazz,
702 android_bluetooth_BluetoothLeAudioContentMetadata.constructor,
703 program_info_str, language_str, raw_metadata.get());
704
705 if (program_info_str) {
706 env->DeleteLocalRef(program_info_str);
707 }
708
709 if (language_str) {
710 env->DeleteLocalRef(language_str);
711 }
712
713 return obj;
714 }
715
prepareLeBroadcastChannelListObject(JNIEnv * env,const std::vector<bluetooth::le_audio::BasicAudioAnnouncementBisConfig> & bis_configs)716 jobject prepareLeBroadcastChannelListObject(
717 JNIEnv* env,
718 const std::vector<bluetooth::le_audio::BasicAudioAnnouncementBisConfig>&
719 bis_configs) {
720 jobject array = env->NewObject(java_util_ArrayList.clazz,
721 java_util_ArrayList.constructor);
722 if (!array) {
723 LOG(ERROR) << "Failed to create array for subgroups";
724 return nullptr;
725 }
726
727 for (const auto& el : bis_configs) {
728 ScopedLocalRef<jobject> channel_obj(
729 env, prepareLeBroadcastChannelObject(env, el));
730 if (!channel_obj.get()) {
731 LOG(ERROR) << "Failed to create new channel object";
732 return nullptr;
733 }
734
735 env->CallBooleanMethod(array, java_util_ArrayList.add, channel_obj.get());
736 }
737 return array;
738 }
739
prepareLeBroadcastSubgroupObject(JNIEnv * env,const bluetooth::le_audio::BasicAudioAnnouncementSubgroup & subgroup)740 jobject prepareLeBroadcastSubgroupObject(
741 JNIEnv* env,
742 const bluetooth::le_audio::BasicAudioAnnouncementSubgroup& subgroup) {
743 // Serialize codec ID
744 jlong jlong_codec_id =
745 subgroup.codec_config.codec_id |
746 ((jlong)subgroup.codec_config.vendor_company_id << 16) |
747 ((jlong)subgroup.codec_config.vendor_codec_id << 32);
748
749 ScopedLocalRef<jobject> codec_config_meta_obj(
750 env, prepareLeAudioCodecConfigMetadataObject(
751 env, subgroup.codec_config.codec_specific_params));
752 if (!codec_config_meta_obj.get()) {
753 LOG(ERROR) << "Failed to create new codec config metadata";
754 return nullptr;
755 }
756
757 ScopedLocalRef<jobject> content_meta_obj(
758 env, prepareLeAudioContentMetadataObject(env, subgroup.metadata));
759 if (!content_meta_obj.get()) {
760 LOG(ERROR) << "Failed to create new codec config metadata";
761 return nullptr;
762 }
763
764 ScopedLocalRef<jobject> channel_list_obj(
765 env, prepareLeBroadcastChannelListObject(env, subgroup.bis_configs));
766 if (!channel_list_obj.get()) {
767 LOG(ERROR) << "Failed to create new codec config metadata";
768 return nullptr;
769 }
770
771 // Create the subgroup
772 return env->NewObject(
773 android_bluetooth_BluetoothLeBroadcastSubgroup.clazz,
774 android_bluetooth_BluetoothLeBroadcastSubgroup.constructor,
775 jlong_codec_id, codec_config_meta_obj.get(), content_meta_obj.get(),
776 channel_list_obj.get());
777 }
778
prepareLeBroadcastSubgroupListObject(JNIEnv * env,const std::vector<bluetooth::le_audio::BasicAudioAnnouncementSubgroup> & subgroup_configs)779 jobject prepareLeBroadcastSubgroupListObject(
780 JNIEnv* env,
781 const std::vector<bluetooth::le_audio::BasicAudioAnnouncementSubgroup>&
782 subgroup_configs) {
783 jobject array = env->NewObject(java_util_ArrayList.clazz,
784 java_util_ArrayList.constructor);
785 if (!array) {
786 LOG(ERROR) << "Failed to create array for subgroups";
787 return nullptr;
788 }
789
790 for (const auto& el : subgroup_configs) {
791 ScopedLocalRef<jobject> subgroup_obj(
792 env, prepareLeBroadcastSubgroupObject(env, el));
793 if (!subgroup_obj.get()) {
794 LOG(ERROR) << "Failed to create new subgroup object";
795 return nullptr;
796 }
797
798 env->CallBooleanMethod(array, java_util_ArrayList.add, subgroup_obj.get());
799 }
800 return array;
801 }
802
prepareBluetoothDeviceObject(JNIEnv * env,const RawAddress & addr,int addr_type)803 jobject prepareBluetoothDeviceObject(JNIEnv* env, const RawAddress& addr,
804 int addr_type) {
805 // The address string has to be uppercase or the BluetoothDevice constructor
806 // will treat it as invalid.
807 auto addr_str = addr.ToString();
808 std::transform(addr_str.begin(), addr_str.end(), addr_str.begin(),
809 [](unsigned char c) { return std::toupper(c); });
810
811 ScopedLocalRef<jstring> addr_jstr(env, env->NewStringUTF(addr_str.c_str()));
812 if (!addr_jstr.get()) {
813 LOG(ERROR) << "Failed to create new preset name String for preset name";
814 return nullptr;
815 }
816
817 return env->NewObject(android_bluetooth_BluetoothDevice.clazz,
818 android_bluetooth_BluetoothDevice.constructor,
819 addr_jstr.get(), (jint)addr_type);
820 }
821
prepareBluetoothLeBroadcastMetadataObject(JNIEnv * env,const bluetooth::le_audio::BroadcastMetadata & broadcast_metadata)822 jobject prepareBluetoothLeBroadcastMetadataObject(
823 JNIEnv* env,
824 const bluetooth::le_audio::BroadcastMetadata& broadcast_metadata) {
825 ScopedLocalRef<jobject> device_obj(
826 env, prepareBluetoothDeviceObject(env, broadcast_metadata.addr,
827 broadcast_metadata.addr_type));
828 if (!device_obj.get()) {
829 LOG(ERROR) << "Failed to create new BluetoothDevice";
830 return nullptr;
831 }
832
833 ScopedLocalRef<jobject> subgroup_list_obj(
834 env,
835 prepareLeBroadcastSubgroupListObject(
836 env, broadcast_metadata.basic_audio_announcement.subgroup_configs));
837 if (!subgroup_list_obj.get()) {
838 LOG(ERROR) << "Failed to create new Subgroup array";
839 return nullptr;
840 }
841
842 // Skip the leading null char bytes
843 int nativeCodeSize = 16;
844 int nativeCodeLeadingZeros = 0;
845 if (broadcast_metadata.broadcast_code) {
846 auto& nativeCode = broadcast_metadata.broadcast_code.value();
847 nativeCodeLeadingZeros =
848 std::find_if(nativeCode.cbegin(), nativeCode.cend(),
849 [](int x) { return x != 0x00; }) -
850 nativeCode.cbegin();
851 nativeCodeSize = nativeCode.size() - nativeCodeLeadingZeros;
852 }
853
854 ScopedLocalRef<jbyteArray> code(env, env->NewByteArray(nativeCodeSize));
855 if (!code.get()) {
856 LOG(ERROR) << "Failed to create new jbyteArray for the broadcast code";
857 return nullptr;
858 }
859
860 if (broadcast_metadata.broadcast_code) {
861 env->SetByteArrayRegion(
862 code.get(), 0, nativeCodeSize,
863 (const jbyte*)broadcast_metadata.broadcast_code->data() +
864 nativeCodeLeadingZeros);
865 CHECK(!env->ExceptionCheck());
866 }
867
868 return env->NewObject(
869 android_bluetooth_BluetoothLeBroadcastMetadata.clazz,
870 android_bluetooth_BluetoothLeBroadcastMetadata.constructor,
871 (jint)broadcast_metadata.addr_type, device_obj.get(),
872 (jint)broadcast_metadata.adv_sid, (jint)broadcast_metadata.broadcast_id,
873 (jint)broadcast_metadata.pa_interval,
874 broadcast_metadata.broadcast_code ? true : false,
875 broadcast_metadata.broadcast_code ? code.get() : nullptr,
876 (jint)broadcast_metadata.basic_audio_announcement.presentation_delay,
877 subgroup_list_obj.get());
878 }
879
880 class LeAudioBroadcasterCallbacksImpl : public LeAudioBroadcasterCallbacks {
881 public:
882 ~LeAudioBroadcasterCallbacksImpl() = default;
883
OnBroadcastCreated(uint32_t broadcast_id,bool success)884 void OnBroadcastCreated(uint32_t broadcast_id, bool success) override {
885 LOG(INFO) << __func__;
886
887 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex);
888 CallbackEnv sCallbackEnv(__func__);
889
890 if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return;
891 sCallbackEnv->CallVoidMethod(sBroadcasterCallbacksObj,
892 method_onBroadcastCreated, (jint)broadcast_id,
893 success ? JNI_TRUE : JNI_FALSE);
894 }
895
OnBroadcastDestroyed(uint32_t broadcast_id)896 void OnBroadcastDestroyed(uint32_t broadcast_id) override {
897 LOG(INFO) << __func__;
898
899 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex);
900 CallbackEnv sCallbackEnv(__func__);
901
902 if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return;
903 sCallbackEnv->CallVoidMethod(sBroadcasterCallbacksObj,
904 method_onBroadcastDestroyed,
905 (jint)broadcast_id);
906 }
907
OnBroadcastStateChanged(uint32_t broadcast_id,BroadcastState state)908 void OnBroadcastStateChanged(uint32_t broadcast_id,
909 BroadcastState state) override {
910 LOG(INFO) << __func__;
911
912 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex);
913 CallbackEnv sCallbackEnv(__func__);
914
915 if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return;
916 sCallbackEnv->CallVoidMethod(
917 sBroadcasterCallbacksObj, method_onBroadcastStateChanged,
918 (jint)broadcast_id,
919 (jint) static_cast<std::underlying_type<BroadcastState>::type>(state));
920 }
921
OnBroadcastMetadataChanged(uint32_t broadcast_id,const bluetooth::le_audio::BroadcastMetadata & broadcast_metadata)922 void OnBroadcastMetadataChanged(uint32_t broadcast_id,
923 const bluetooth::le_audio::BroadcastMetadata&
924 broadcast_metadata) override {
925 LOG(INFO) << __func__;
926
927 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex);
928 CallbackEnv sCallbackEnv(__func__);
929
930 ScopedLocalRef<jobject> metadata_obj(
931 sCallbackEnv.get(), prepareBluetoothLeBroadcastMetadataObject(
932 sCallbackEnv.get(), broadcast_metadata));
933
934 if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return;
935 sCallbackEnv->CallVoidMethod(sBroadcasterCallbacksObj,
936 method_onBroadcastMetadataChanged,
937 (jint)broadcast_id, metadata_obj.get());
938 }
939 };
940
941 static LeAudioBroadcasterCallbacksImpl sLeAudioBroadcasterCallbacks;
942
BroadcasterClassInitNative(JNIEnv * env,jclass clazz)943 static void BroadcasterClassInitNative(JNIEnv* env, jclass clazz) {
944 method_onBroadcastCreated =
945 env->GetMethodID(clazz, "onBroadcastCreated", "(IZ)V");
946 method_onBroadcastDestroyed =
947 env->GetMethodID(clazz, "onBroadcastDestroyed", "(I)V");
948 method_onBroadcastStateChanged =
949 env->GetMethodID(clazz, "onBroadcastStateChanged", "(II)V");
950 method_onBroadcastMetadataChanged =
951 env->GetMethodID(clazz, "onBroadcastMetadataChanged",
952 "(ILandroid/bluetooth/BluetoothLeBroadcastMetadata;)V");
953
954 jclass jniArrayListClass = env->FindClass("java/util/ArrayList");
955 java_util_ArrayList.constructor =
956 env->GetMethodID(jniArrayListClass, "<init>", "()V");
957 java_util_ArrayList.add =
958 env->GetMethodID(jniArrayListClass, "add", "(Ljava/lang/Object;)Z");
959
960 jclass jniBluetoothLeAudioCodecConfigMetadataClass =
961 env->FindClass("android/bluetooth/BluetoothLeAudioCodecConfigMetadata");
962 android_bluetooth_BluetoothLeAudioCodecConfigMetadata.constructor =
963 env->GetMethodID(jniBluetoothLeAudioCodecConfigMetadataClass, "<init>",
964 "(J[B)V");
965
966 jclass jniBluetoothLeAudioContentMetadataClass =
967 env->FindClass("android/bluetooth/BluetoothLeAudioContentMetadata");
968 android_bluetooth_BluetoothLeAudioContentMetadata.constructor =
969 env->GetMethodID(jniBluetoothLeAudioContentMetadataClass, "<init>",
970 "(Ljava/lang/String;Ljava/lang/String;[B)V");
971
972 jclass jniBluetoothLeBroadcastChannelClass =
973 env->FindClass("android/bluetooth/BluetoothLeBroadcastChannel");
974 android_bluetooth_BluetoothLeBroadcastChannel.constructor = env->GetMethodID(
975 jniBluetoothLeBroadcastChannelClass, "<init>",
976 "(ZILandroid/bluetooth/BluetoothLeAudioCodecConfigMetadata;)V");
977
978 jclass jniBluetoothLeBroadcastSubgroupClass =
979 env->FindClass("android/bluetooth/BluetoothLeBroadcastSubgroup");
980 android_bluetooth_BluetoothLeBroadcastSubgroup.constructor = env->GetMethodID(
981 jniBluetoothLeBroadcastSubgroupClass, "<init>",
982 "(JLandroid/bluetooth/BluetoothLeAudioCodecConfigMetadata;"
983 "Landroid/bluetooth/BluetoothLeAudioContentMetadata;"
984 "Ljava/util/List;)V");
985
986 jclass jniBluetoothDeviceClass =
987 env->FindClass("android/bluetooth/BluetoothDevice");
988 android_bluetooth_BluetoothDevice.constructor = env->GetMethodID(
989 jniBluetoothDeviceClass, "<init>", "(Ljava/lang/String;I)V");
990
991 jclass jniBluetoothLeBroadcastMetadataClass =
992 env->FindClass("android/bluetooth/BluetoothLeBroadcastMetadata");
993 android_bluetooth_BluetoothLeBroadcastMetadata.constructor = env->GetMethodID(
994 jniBluetoothLeBroadcastMetadataClass, "<init>",
995 "(ILandroid/bluetooth/BluetoothDevice;IIIZ[BILjava/util/List;)V");
996 }
997
BroadcasterInitNative(JNIEnv * env,jobject object)998 static void BroadcasterInitNative(JNIEnv* env, jobject object) {
999 std::unique_lock<std::shared_timed_mutex> interface_lock(
1000 sBroadcasterInterfaceMutex);
1001 std::unique_lock<std::shared_timed_mutex> callbacks_lock(
1002 sBroadcasterCallbacksMutex);
1003
1004 const bt_interface_t* btInf = getBluetoothInterface();
1005 if (btInf == nullptr) {
1006 LOG(ERROR) << "Bluetooth module is not loaded";
1007 return;
1008 }
1009
1010 android_bluetooth_BluetoothDevice.clazz = (jclass)env->NewGlobalRef(
1011 env->FindClass("android/bluetooth/BluetoothDevice"));
1012 if (android_bluetooth_BluetoothDevice.clazz == nullptr) {
1013 LOG(ERROR) << "Failed to allocate Global Ref for BluetoothDevice class";
1014 return;
1015 }
1016
1017 java_util_ArrayList.clazz =
1018 (jclass)env->NewGlobalRef(env->FindClass("java/util/ArrayList"));
1019 if (java_util_ArrayList.clazz == nullptr) {
1020 LOG(ERROR) << "Failed to allocate Global Ref for ArrayList class";
1021 return;
1022 }
1023
1024 android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz =
1025 (jclass)env->NewGlobalRef(env->FindClass(
1026 "android/bluetooth/BluetoothLeAudioCodecConfigMetadata"));
1027 if (android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz == nullptr) {
1028 LOG(ERROR) << "Failed to allocate Global Ref for "
1029 "BluetoothLeAudioCodecConfigMetadata class";
1030 return;
1031 }
1032
1033 android_bluetooth_BluetoothLeAudioContentMetadata.clazz =
1034 (jclass)env->NewGlobalRef(
1035 env->FindClass("android/bluetooth/BluetoothLeAudioContentMetadata"));
1036 if (android_bluetooth_BluetoothLeAudioContentMetadata.clazz == nullptr) {
1037 LOG(ERROR) << "Failed to allocate Global Ref for "
1038 "BluetoothLeAudioContentMetadata class";
1039 return;
1040 }
1041
1042 android_bluetooth_BluetoothLeBroadcastSubgroup.clazz =
1043 (jclass)env->NewGlobalRef(
1044 env->FindClass("android/bluetooth/BluetoothLeBroadcastSubgroup"));
1045 if (android_bluetooth_BluetoothLeBroadcastSubgroup.clazz == nullptr) {
1046 LOG(ERROR) << "Failed to allocate Global Ref for "
1047 "BluetoothLeBroadcastSubgroup class";
1048 return;
1049 }
1050
1051 android_bluetooth_BluetoothLeBroadcastChannel.clazz =
1052 (jclass)env->NewGlobalRef(
1053 env->FindClass("android/bluetooth/BluetoothLeBroadcastChannel"));
1054 if (android_bluetooth_BluetoothLeBroadcastChannel.clazz == nullptr) {
1055 LOG(ERROR) << "Failed to allocate Global Ref for "
1056 "BluetoothLeBroadcastChannel class";
1057 return;
1058 }
1059
1060 android_bluetooth_BluetoothLeBroadcastMetadata.clazz =
1061 (jclass)env->NewGlobalRef(
1062 env->FindClass("android/bluetooth/BluetoothLeBroadcastMetadata"));
1063 if (android_bluetooth_BluetoothLeBroadcastMetadata.clazz == nullptr) {
1064 LOG(ERROR) << "Failed to allocate Global Ref for "
1065 "BluetoothLeBroadcastMetadata class";
1066 return;
1067 }
1068
1069 if (sBroadcasterCallbacksObj != nullptr) {
1070 LOG(INFO) << "Cleaning up LeAudio Broadcaster callback object";
1071 env->DeleteGlobalRef(sBroadcasterCallbacksObj);
1072 sBroadcasterCallbacksObj = nullptr;
1073 }
1074
1075 if ((sBroadcasterCallbacksObj = env->NewGlobalRef(object)) == nullptr) {
1076 LOG(ERROR)
1077 << "Failed to allocate Global Ref for LeAudio Broadcaster Callbacks";
1078 return;
1079 }
1080
1081 sLeAudioBroadcasterInterface =
1082 (LeAudioBroadcasterInterface*)btInf->get_profile_interface(
1083 BT_PROFILE_LE_AUDIO_BROADCASTER_ID);
1084 if (sLeAudioBroadcasterInterface == nullptr) {
1085 LOG(ERROR) << "Failed to get Bluetooth LeAudio Broadcaster Interface";
1086 return;
1087 }
1088
1089 sLeAudioBroadcasterInterface->Initialize(&sLeAudioBroadcasterCallbacks);
1090 }
1091
BroadcasterStopNative(JNIEnv * env,jobject object)1092 static void BroadcasterStopNative(JNIEnv* env, jobject object) {
1093 std::unique_lock<std::shared_timed_mutex> interface_lock(
1094 sBroadcasterInterfaceMutex);
1095
1096 const bt_interface_t* btInf = getBluetoothInterface();
1097 if (btInf == nullptr) {
1098 LOG(ERROR) << "Bluetooth module is not loaded";
1099 return;
1100 }
1101
1102 if (sLeAudioBroadcasterInterface != nullptr)
1103 sLeAudioBroadcasterInterface->Stop();
1104 }
1105
BroadcasterCleanupNative(JNIEnv * env,jobject object)1106 static void BroadcasterCleanupNative(JNIEnv* env, jobject object) {
1107 std::unique_lock<std::shared_timed_mutex> interface_lock(
1108 sBroadcasterInterfaceMutex);
1109 std::unique_lock<std::shared_timed_mutex> callbacks_lock(
1110 sBroadcasterCallbacksMutex);
1111
1112 const bt_interface_t* btInf = getBluetoothInterface();
1113 if (btInf == nullptr) {
1114 LOG(ERROR) << "Bluetooth module is not loaded";
1115 return;
1116 }
1117
1118 env->DeleteGlobalRef(java_util_ArrayList.clazz);
1119 java_util_ArrayList.clazz = nullptr;
1120
1121 env->DeleteGlobalRef(android_bluetooth_BluetoothDevice.clazz);
1122 android_bluetooth_BluetoothDevice.clazz = nullptr;
1123
1124 env->DeleteGlobalRef(
1125 android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz);
1126 android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz = nullptr;
1127
1128 env->DeleteGlobalRef(android_bluetooth_BluetoothLeAudioContentMetadata.clazz);
1129 android_bluetooth_BluetoothLeAudioContentMetadata.clazz = nullptr;
1130
1131 env->DeleteGlobalRef(android_bluetooth_BluetoothLeBroadcastSubgroup.clazz);
1132 android_bluetooth_BluetoothLeBroadcastSubgroup.clazz = nullptr;
1133
1134 env->DeleteGlobalRef(android_bluetooth_BluetoothLeBroadcastChannel.clazz);
1135 android_bluetooth_BluetoothLeBroadcastChannel.clazz = nullptr;
1136
1137 env->DeleteGlobalRef(android_bluetooth_BluetoothLeBroadcastMetadata.clazz);
1138 android_bluetooth_BluetoothLeBroadcastMetadata.clazz = nullptr;
1139
1140 if (sLeAudioBroadcasterInterface != nullptr) {
1141 sLeAudioBroadcasterInterface->Cleanup();
1142 sLeAudioBroadcasterInterface = nullptr;
1143 }
1144
1145 if (sBroadcasterCallbacksObj != nullptr) {
1146 env->DeleteGlobalRef(sBroadcasterCallbacksObj);
1147 sBroadcasterCallbacksObj = nullptr;
1148 }
1149 }
1150
CreateBroadcastNative(JNIEnv * env,jobject object,jbyteArray metadata,jbyteArray broadcast_code)1151 static void CreateBroadcastNative(JNIEnv* env, jobject object,
1152 jbyteArray metadata,
1153 jbyteArray broadcast_code) {
1154 LOG(INFO) << __func__;
1155 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1156 if (!sLeAudioBroadcasterInterface) return;
1157
1158 std::array<uint8_t, 16> code_array{0};
1159 if (broadcast_code) {
1160 jsize size = env->GetArrayLength(broadcast_code);
1161 if (size > 16) {
1162 ALOGE("%s: broadcast code to long", __func__);
1163 return;
1164 }
1165
1166 // Padding with zeros on LSB positions if code is shorter than 16 octets
1167 env->GetByteArrayRegion(
1168 broadcast_code, 0, size,
1169 (jbyte*)code_array.data() + code_array.size() - size);
1170 }
1171
1172 jbyte* meta = env->GetByteArrayElements(metadata, nullptr);
1173 sLeAudioBroadcasterInterface->CreateBroadcast(
1174 std::vector<uint8_t>(meta, meta + env->GetArrayLength(metadata)),
1175 broadcast_code ? std::optional<std::array<uint8_t, 16>>(code_array)
1176 : std::nullopt);
1177 env->ReleaseByteArrayElements(metadata, meta, 0);
1178 }
1179
UpdateMetadataNative(JNIEnv * env,jobject object,jint broadcast_id,jbyteArray metadata)1180 static void UpdateMetadataNative(JNIEnv* env, jobject object, jint broadcast_id,
1181 jbyteArray metadata) {
1182 jbyte* meta = env->GetByteArrayElements(metadata, nullptr);
1183 sLeAudioBroadcasterInterface->UpdateMetadata(
1184 broadcast_id,
1185 std::vector<uint8_t>(meta, meta + env->GetArrayLength(metadata)));
1186 env->ReleaseByteArrayElements(metadata, meta, 0);
1187 }
1188
StartBroadcastNative(JNIEnv * env,jobject object,jint broadcast_id)1189 static void StartBroadcastNative(JNIEnv* env, jobject object,
1190 jint broadcast_id) {
1191 LOG(INFO) << __func__;
1192 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1193 if (!sLeAudioBroadcasterInterface) return;
1194 sLeAudioBroadcasterInterface->StartBroadcast(broadcast_id);
1195 }
1196
StopBroadcastNative(JNIEnv * env,jobject object,jint broadcast_id)1197 static void StopBroadcastNative(JNIEnv* env, jobject object,
1198 jint broadcast_id) {
1199 LOG(INFO) << __func__;
1200 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1201 if (!sLeAudioBroadcasterInterface) return;
1202 sLeAudioBroadcasterInterface->StopBroadcast(broadcast_id);
1203 }
1204
PauseBroadcastNative(JNIEnv * env,jobject object,jint broadcast_id)1205 static void PauseBroadcastNative(JNIEnv* env, jobject object,
1206 jint broadcast_id) {
1207 LOG(INFO) << __func__;
1208 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1209 if (!sLeAudioBroadcasterInterface) return;
1210 sLeAudioBroadcasterInterface->PauseBroadcast(broadcast_id);
1211 }
1212
DestroyBroadcastNative(JNIEnv * env,jobject object,jint broadcast_id)1213 static void DestroyBroadcastNative(JNIEnv* env, jobject object,
1214 jint broadcast_id) {
1215 LOG(INFO) << __func__;
1216 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1217 if (!sLeAudioBroadcasterInterface) return;
1218 sLeAudioBroadcasterInterface->DestroyBroadcast(broadcast_id);
1219 }
1220
getBroadcastMetadataNative(JNIEnv * env,jobject object,jint broadcast_id)1221 static void getBroadcastMetadataNative(JNIEnv* env, jobject object,
1222 jint broadcast_id) {
1223 LOG(INFO) << __func__;
1224 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1225 if (!sLeAudioBroadcasterInterface) return;
1226 sLeAudioBroadcasterInterface->GetBroadcastMetadata(broadcast_id);
1227 }
1228
1229 static JNINativeMethod sBroadcasterMethods[] = {
1230 {"classInitNative", "()V", (void*)BroadcasterClassInitNative},
1231 {"initNative", "()V", (void*)BroadcasterInitNative},
1232 {"stopNative", "()V", (void*)BroadcasterStopNative},
1233 {"cleanupNative", "()V", (void*)BroadcasterCleanupNative},
1234 {"createBroadcastNative", "([B[B)V", (void*)CreateBroadcastNative},
1235 {"updateMetadataNative", "(I[B)V", (void*)UpdateMetadataNative},
1236 {"startBroadcastNative", "(I)V", (void*)StartBroadcastNative},
1237 {"stopBroadcastNative", "(I)V", (void*)StopBroadcastNative},
1238 {"pauseBroadcastNative", "(I)V", (void*)PauseBroadcastNative},
1239 {"destroyBroadcastNative", "(I)V", (void*)DestroyBroadcastNative},
1240 {"getBroadcastMetadataNative", "(I)V", (void*)getBroadcastMetadataNative},
1241 };
1242
register_com_android_bluetooth_le_audio(JNIEnv * env)1243 int register_com_android_bluetooth_le_audio(JNIEnv* env) {
1244 int register_success = jniRegisterNativeMethods(
1245 env, "com/android/bluetooth/le_audio/LeAudioNativeInterface", sMethods,
1246 NELEM(sMethods));
1247 return register_success &
1248 jniRegisterNativeMethods(
1249 env,
1250 "com/android/bluetooth/le_audio/LeAudioBroadcasterNativeInterface",
1251 sBroadcasterMethods, NELEM(sBroadcasterMethods));
1252 }
1253 } // namespace android
1254