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
setEnableStateNative(JNIEnv * env,jobject object,jbyteArray address,jboolean enabled)438 static jboolean setEnableStateNative(JNIEnv* env, jobject object,
439 jbyteArray address, jboolean enabled) {
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->SetEnableState(*tmpraw, enabled);
455 env->ReleaseByteArrayElements(address, addr, 0);
456 return JNI_TRUE;
457 }
458
groupAddNodeNative(JNIEnv * env,jobject object,jint group_id,jbyteArray address)459 static jboolean groupAddNodeNative(JNIEnv* env, jobject object, jint group_id,
460 jbyteArray address) {
461 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
462 jbyte* addr = env->GetByteArrayElements(address, nullptr);
463
464 if (!sLeAudioClientInterface) {
465 LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface";
466 return JNI_FALSE;
467 }
468
469 if (!addr) {
470 jniThrowIOException(env, EINVAL);
471 return JNI_FALSE;
472 }
473
474 RawAddress* tmpraw = (RawAddress*)addr;
475 sLeAudioClientInterface->GroupAddNode(group_id, *tmpraw);
476 env->ReleaseByteArrayElements(address, addr, 0);
477
478 return JNI_TRUE;
479 }
480
groupRemoveNodeNative(JNIEnv * env,jobject object,jint group_id,jbyteArray address)481 static jboolean groupRemoveNodeNative(JNIEnv* env, jobject object,
482 jint group_id, jbyteArray address) {
483 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
484 if (!sLeAudioClientInterface) {
485 LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface";
486 return JNI_FALSE;
487 }
488
489 jbyte* addr = env->GetByteArrayElements(address, nullptr);
490 if (!addr) {
491 jniThrowIOException(env, EINVAL);
492 return JNI_FALSE;
493 }
494
495 RawAddress* tmpraw = (RawAddress*)addr;
496 sLeAudioClientInterface->GroupRemoveNode(group_id, *tmpraw);
497 env->ReleaseByteArrayElements(address, addr, 0);
498 return JNI_TRUE;
499 }
500
groupSetActiveNative(JNIEnv * env,jobject object,jint group_id)501 static void groupSetActiveNative(JNIEnv* env, jobject object, jint group_id) {
502 LOG(INFO) << __func__;
503 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
504
505 if (!sLeAudioClientInterface) {
506 LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface";
507 return;
508 }
509
510 sLeAudioClientInterface->GroupSetActive(group_id);
511 }
512
setCodecConfigPreferenceNative(JNIEnv * env,jobject object,jint group_id,jobject inputCodecConfig,jobject outputCodecConfig)513 static void setCodecConfigPreferenceNative(JNIEnv* env, jobject object,
514 jint group_id,
515 jobject inputCodecConfig,
516 jobject outputCodecConfig) {
517 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
518
519 if (!env->IsInstanceOf(inputCodecConfig,
520 android_bluetooth_BluetoothLeAudioCodecConfig.clazz) ||
521 !env->IsInstanceOf(outputCodecConfig,
522 android_bluetooth_BluetoothLeAudioCodecConfig.clazz)) {
523 ALOGE("%s: Invalid BluetoothLeAudioCodecConfig instance", __func__);
524 return;
525 }
526
527 jint inputCodecType = env->CallIntMethod(
528 inputCodecConfig,
529 android_bluetooth_BluetoothLeAudioCodecConfig.getCodecType);
530
531 btle_audio_codec_config_t input_codec_config = {
532 .codec_type = static_cast<btle_audio_codec_index_t>(inputCodecType)};
533
534 jint outputCodecType = env->CallIntMethod(
535 outputCodecConfig,
536 android_bluetooth_BluetoothLeAudioCodecConfig.getCodecType);
537
538 btle_audio_codec_config_t output_codec_config = {
539 .codec_type = static_cast<btle_audio_codec_index_t>(outputCodecType)};
540
541 sLeAudioClientInterface->SetCodecConfigPreference(
542 group_id, input_codec_config, output_codec_config);
543 }
544
setCcidInformationNative(JNIEnv * env,jobject object,jint ccid,jint contextType)545 static void setCcidInformationNative(JNIEnv* env, jobject object, jint ccid,
546 jint contextType) {
547 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
548 if (!sLeAudioClientInterface) {
549 LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface";
550 return;
551 }
552
553 sLeAudioClientInterface->SetCcidInformation(ccid, contextType);
554 }
555
setInCallNative(JNIEnv * env,jobject object,jboolean inCall)556 static void setInCallNative(JNIEnv* env, jobject object, jboolean inCall) {
557 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
558 if (!sLeAudioClientInterface) {
559 LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface";
560 return;
561 }
562
563 sLeAudioClientInterface->SetInCall(inCall);
564 }
565
sendAudioProfilePreferencesNative(JNIEnv * env,jint groupId,jboolean isOutputPreferenceLeAudio,jboolean isDuplexPreferenceLeAudio)566 static void sendAudioProfilePreferencesNative(
567 JNIEnv* env, jint groupId, jboolean isOutputPreferenceLeAudio,
568 jboolean isDuplexPreferenceLeAudio) {
569 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
570 if (!sLeAudioClientInterface) {
571 LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface";
572 return;
573 }
574
575 sLeAudioClientInterface->SendAudioProfilePreferences(
576 groupId, isOutputPreferenceLeAudio, isDuplexPreferenceLeAudio);
577 }
578
579 static JNINativeMethod sMethods[] = {
580 {"classInitNative", "()V", (void*)classInitNative},
581 {"initNative", "([Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V",
582 (void*)initNative},
583 {"cleanupNative", "()V", (void*)cleanupNative},
584 {"connectLeAudioNative", "([B)Z", (void*)connectLeAudioNative},
585 {"disconnectLeAudioNative", "([B)Z", (void*)disconnectLeAudioNative},
586 {"setEnableStateNative", "([BZ)Z", (void*)setEnableStateNative},
587 {"groupAddNodeNative", "(I[B)Z", (void*)groupAddNodeNative},
588 {"groupRemoveNodeNative", "(I[B)Z", (void*)groupRemoveNodeNative},
589 {"groupSetActiveNative", "(I)V", (void*)groupSetActiveNative},
590 {"setCodecConfigPreferenceNative",
591 "(ILandroid/bluetooth/BluetoothLeAudioCodecConfig;Landroid/bluetooth/"
592 "BluetoothLeAudioCodecConfig;)V",
593 (void*)setCodecConfigPreferenceNative},
594 {"setCcidInformationNative", "(II)V", (void*)setCcidInformationNative},
595 {"setInCallNative", "(Z)V", (void*)setInCallNative},
596 {"sendAudioProfilePreferencesNative", "(IZZ)V",
597 (void*)sendAudioProfilePreferencesNative},
598 };
599
600 /* Le Audio Broadcaster */
601 static jmethodID method_onBroadcastCreated;
602 static jmethodID method_onBroadcastDestroyed;
603 static jmethodID method_onBroadcastStateChanged;
604 static jmethodID method_onBroadcastMetadataChanged;
605
606 static LeAudioBroadcasterInterface* sLeAudioBroadcasterInterface = nullptr;
607 static std::shared_timed_mutex sBroadcasterInterfaceMutex;
608
609 static jobject sBroadcasterCallbacksObj = nullptr;
610 static std::shared_timed_mutex sBroadcasterCallbacksMutex;
611
612 #define VEC_UINT8_TO_UINT32(vec) \
613 ((vec.data()[3] << 24) + (vec.data()[2] << 16) + (vec.data()[1] << 8) + \
614 vec.data()[0])
615
616 #define VEC_UINT8_TO_UINT16(vec) (((vec).data()[1] << 8) + ((vec).data()[0]))
617
RawPacketSize(const std::map<uint8_t,std::vector<uint8_t>> & values)618 size_t RawPacketSize(const std::map<uint8_t, std::vector<uint8_t>>& values) {
619 size_t bytes = 0;
620 for (auto const& value : values) {
621 bytes += (/* ltv_len + ltv_type */ 2 + value.second.size());
622 }
623 return bytes;
624 }
625
prepareRawLtvArray(JNIEnv * env,const std::map<uint8_t,std::vector<uint8_t>> & metadata)626 jbyteArray prepareRawLtvArray(
627 JNIEnv* env, const std::map<uint8_t, std::vector<uint8_t>>& metadata) {
628 auto raw_meta_size = RawPacketSize(metadata);
629
630 jbyteArray raw_metadata = env->NewByteArray(raw_meta_size);
631 if (!raw_metadata) {
632 LOG(ERROR) << "Failed to create new jbyteArray for raw LTV";
633 return nullptr;
634 }
635
636 jsize offset = 0;
637 for (auto const& kv_pair : metadata) {
638 // Length
639 const jbyte ltv_sz = kv_pair.second.size() + 1;
640 env->SetByteArrayRegion(raw_metadata, offset, 1, <v_sz);
641 offset += 1;
642 // Type
643 env->SetByteArrayRegion(raw_metadata, offset, 1,
644 (const jbyte*)&kv_pair.first);
645 offset += 1;
646 // Value
647 env->SetByteArrayRegion(raw_metadata, offset, kv_pair.second.size(),
648 (const jbyte*)kv_pair.second.data());
649 offset += kv_pair.second.size();
650 }
651
652 return raw_metadata;
653 }
654
getAudioLocationOrDefault(const std::map<uint8_t,std::vector<uint8_t>> & metadata,jlong default_location)655 static jlong getAudioLocationOrDefault(
656 const std::map<uint8_t, std::vector<uint8_t>>& metadata,
657 jlong default_location) {
658 if (metadata.count(
659 bluetooth::le_audio::kLeAudioCodecLC3TypeAudioChannelAllocation) == 0)
660 return default_location;
661
662 auto& vec = metadata.at(
663 bluetooth::le_audio::kLeAudioCodecLC3TypeAudioChannelAllocation);
664 return VEC_UINT8_TO_UINT32(vec);
665 }
666
getSamplingFrequencyOrDefault(const std::map<uint8_t,std::vector<uint8_t>> & metadata,jint default_sampling_frequency)667 static jint getSamplingFrequencyOrDefault(
668 const std::map<uint8_t, std::vector<uint8_t>>& metadata,
669 jint default_sampling_frequency) {
670 if (metadata.count(bluetooth::le_audio::kLeAudioCodecLC3TypeSamplingFreq) ==
671 0)
672 return default_sampling_frequency;
673
674 auto& vec =
675 metadata.at(bluetooth::le_audio::kLeAudioCodecLC3TypeSamplingFreq);
676 return (jint)(vec.data()[0]);
677 }
678
getFrameDurationOrDefault(const std::map<uint8_t,std::vector<uint8_t>> & metadata,jint default_frame_duration)679 static jint getFrameDurationOrDefault(
680 const std::map<uint8_t, std::vector<uint8_t>>& metadata,
681 jint default_frame_duration) {
682 if (metadata.count(bluetooth::le_audio::kLeAudioCodecLC3TypeFrameDuration) ==
683 0)
684 return default_frame_duration;
685
686 auto& vec =
687 metadata.at(bluetooth::le_audio::kLeAudioCodecLC3TypeFrameDuration);
688 return (jint)(vec.data()[0]);
689 }
690
getOctetsPerFrameOrDefault(const std::map<uint8_t,std::vector<uint8_t>> & metadata,jint default_octets_per_frame)691 static jint getOctetsPerFrameOrDefault(
692 const std::map<uint8_t, std::vector<uint8_t>>& metadata,
693 jint default_octets_per_frame) {
694 if (metadata.count(bluetooth::le_audio::kLeAudioCodecLC3TypeOctetPerFrame) ==
695 0)
696 return default_octets_per_frame;
697
698 auto& vec =
699 metadata.at(bluetooth::le_audio::kLeAudioCodecLC3TypeOctetPerFrame);
700 return VEC_UINT8_TO_UINT16(vec);
701 }
702
prepareLeAudioCodecConfigMetadataObject(JNIEnv * env,const std::map<uint8_t,std::vector<uint8_t>> & metadata)703 jobject prepareLeAudioCodecConfigMetadataObject(
704 JNIEnv* env, const std::map<uint8_t, std::vector<uint8_t>>& metadata) {
705 jlong audio_location = getAudioLocationOrDefault(metadata, -1);
706 jint sampling_frequency = getSamplingFrequencyOrDefault(metadata, 0);
707 jint frame_duration = getFrameDurationOrDefault(metadata, -1);
708 jint octets_per_frame = getOctetsPerFrameOrDefault(metadata, 0);
709 ScopedLocalRef<jbyteArray> raw_metadata(env,
710 prepareRawLtvArray(env, metadata));
711 if (!raw_metadata.get()) {
712 LOG(ERROR) << "Failed to create raw metadata jbyteArray";
713 return nullptr;
714 }
715
716 jobject obj = env->NewObject(
717 android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz,
718 android_bluetooth_BluetoothLeAudioCodecConfigMetadata.constructor,
719 audio_location, sampling_frequency, frame_duration, octets_per_frame,
720 raw_metadata.get());
721
722 return obj;
723 }
724
prepareLeBroadcastChannelObject(JNIEnv * env,const bluetooth::le_audio::BasicAudioAnnouncementBisConfig & bis_config)725 jobject prepareLeBroadcastChannelObject(
726 JNIEnv* env,
727 const bluetooth::le_audio::BasicAudioAnnouncementBisConfig& bis_config) {
728 ScopedLocalRef<jobject> meta_object(
729 env, prepareLeAudioCodecConfigMetadataObject(
730 env, bis_config.codec_specific_params));
731 if (!meta_object.get()) {
732 LOG(ERROR) << "Failed to create new metadata object for bis config";
733 return nullptr;
734 }
735
736 jobject obj =
737 env->NewObject(android_bluetooth_BluetoothLeBroadcastChannel.clazz,
738 android_bluetooth_BluetoothLeBroadcastChannel.constructor,
739 false, bis_config.bis_index, meta_object.get());
740
741 return obj;
742 }
743
prepareLeAudioContentMetadataObject(JNIEnv * env,const std::map<uint8_t,std::vector<uint8_t>> & metadata)744 jobject prepareLeAudioContentMetadataObject(
745 JNIEnv* env, const std::map<uint8_t, std::vector<uint8_t>>& metadata) {
746 jstring program_info_str = nullptr;
747 if (metadata.count(bluetooth::le_audio::kLeAudioMetadataTypeProgramInfo)) {
748 program_info_str = env->NewStringUTF(
749 (const char*)(metadata
750 .at(bluetooth::le_audio::
751 kLeAudioMetadataTypeProgramInfo)
752 .data()));
753 if (!program_info_str) {
754 LOG(ERROR) << "Failed to create new preset name String for preset name";
755 return nullptr;
756 }
757 }
758
759 jstring language_str = nullptr;
760 if (metadata.count(bluetooth::le_audio::kLeAudioMetadataTypeLanguage)) {
761 language_str = env->NewStringUTF(
762 (const char*)(metadata
763 .at(bluetooth::le_audio::kLeAudioMetadataTypeLanguage)
764 .data()));
765 if (!language_str) {
766 LOG(ERROR) << "Failed to create new preset name String for language";
767 return nullptr;
768 }
769 }
770
771 // This can be nullptr
772 ScopedLocalRef<jbyteArray> raw_metadata(env,
773 prepareRawLtvArray(env, metadata));
774 if (!raw_metadata.get()) {
775 LOG(ERROR) << "Failed to create raw_metadata jbyteArray";
776 return nullptr;
777 }
778
779 jobject obj = env->NewObject(
780 android_bluetooth_BluetoothLeAudioContentMetadata.clazz,
781 android_bluetooth_BluetoothLeAudioContentMetadata.constructor,
782 program_info_str, language_str, raw_metadata.get());
783
784 if (program_info_str) {
785 env->DeleteLocalRef(program_info_str);
786 }
787
788 if (language_str) {
789 env->DeleteLocalRef(language_str);
790 }
791
792 return obj;
793 }
794
prepareLeBroadcastChannelListObject(JNIEnv * env,const std::vector<bluetooth::le_audio::BasicAudioAnnouncementBisConfig> & bis_configs)795 jobject prepareLeBroadcastChannelListObject(
796 JNIEnv* env,
797 const std::vector<bluetooth::le_audio::BasicAudioAnnouncementBisConfig>&
798 bis_configs) {
799 jobject array = env->NewObject(java_util_ArrayList.clazz,
800 java_util_ArrayList.constructor);
801 if (!array) {
802 LOG(ERROR) << "Failed to create array for subgroups";
803 return nullptr;
804 }
805
806 for (const auto& el : bis_configs) {
807 ScopedLocalRef<jobject> channel_obj(
808 env, prepareLeBroadcastChannelObject(env, el));
809 if (!channel_obj.get()) {
810 LOG(ERROR) << "Failed to create new channel object";
811 return nullptr;
812 }
813
814 env->CallBooleanMethod(array, java_util_ArrayList.add, channel_obj.get());
815 }
816 return array;
817 }
818
prepareLeBroadcastSubgroupObject(JNIEnv * env,const bluetooth::le_audio::BasicAudioAnnouncementSubgroup & subgroup)819 jobject prepareLeBroadcastSubgroupObject(
820 JNIEnv* env,
821 const bluetooth::le_audio::BasicAudioAnnouncementSubgroup& subgroup) {
822 // Serialize codec ID
823 jlong jlong_codec_id =
824 subgroup.codec_config.codec_id |
825 ((jlong)subgroup.codec_config.vendor_company_id << 16) |
826 ((jlong)subgroup.codec_config.vendor_codec_id << 32);
827
828 ScopedLocalRef<jobject> codec_config_meta_obj(
829 env, prepareLeAudioCodecConfigMetadataObject(
830 env, subgroup.codec_config.codec_specific_params));
831 if (!codec_config_meta_obj.get()) {
832 LOG(ERROR) << "Failed to create new codec config metadata";
833 return nullptr;
834 }
835
836 ScopedLocalRef<jobject> content_meta_obj(
837 env, prepareLeAudioContentMetadataObject(env, subgroup.metadata));
838 if (!content_meta_obj.get()) {
839 LOG(ERROR) << "Failed to create new codec config metadata";
840 return nullptr;
841 }
842
843 ScopedLocalRef<jobject> channel_list_obj(
844 env, prepareLeBroadcastChannelListObject(env, subgroup.bis_configs));
845 if (!channel_list_obj.get()) {
846 LOG(ERROR) << "Failed to create new codec config metadata";
847 return nullptr;
848 }
849
850 // Create the subgroup
851 return env->NewObject(
852 android_bluetooth_BluetoothLeBroadcastSubgroup.clazz,
853 android_bluetooth_BluetoothLeBroadcastSubgroup.constructor,
854 jlong_codec_id, codec_config_meta_obj.get(), content_meta_obj.get(),
855 channel_list_obj.get());
856 }
857
prepareLeBroadcastSubgroupListObject(JNIEnv * env,const std::vector<bluetooth::le_audio::BasicAudioAnnouncementSubgroup> & subgroup_configs)858 jobject prepareLeBroadcastSubgroupListObject(
859 JNIEnv* env,
860 const std::vector<bluetooth::le_audio::BasicAudioAnnouncementSubgroup>&
861 subgroup_configs) {
862 jobject array = env->NewObject(java_util_ArrayList.clazz,
863 java_util_ArrayList.constructor);
864 if (!array) {
865 LOG(ERROR) << "Failed to create array for subgroups";
866 return nullptr;
867 }
868
869 for (const auto& el : subgroup_configs) {
870 ScopedLocalRef<jobject> subgroup_obj(
871 env, prepareLeBroadcastSubgroupObject(env, el));
872 if (!subgroup_obj.get()) {
873 LOG(ERROR) << "Failed to create new subgroup object";
874 return nullptr;
875 }
876
877 env->CallBooleanMethod(array, java_util_ArrayList.add, subgroup_obj.get());
878 }
879 return array;
880 }
881
prepareBluetoothDeviceObject(JNIEnv * env,const RawAddress & addr,int addr_type)882 jobject prepareBluetoothDeviceObject(JNIEnv* env, const RawAddress& addr,
883 int addr_type) {
884 // The address string has to be uppercase or the BluetoothDevice constructor
885 // will treat it as invalid.
886 auto addr_str = addr.ToString();
887 std::transform(addr_str.begin(), addr_str.end(), addr_str.begin(),
888 [](unsigned char c) { return std::toupper(c); });
889
890 ScopedLocalRef<jstring> addr_jstr(env, env->NewStringUTF(addr_str.c_str()));
891 if (!addr_jstr.get()) {
892 LOG(ERROR) << "Failed to create new preset name String for preset name";
893 return nullptr;
894 }
895
896 return env->NewObject(android_bluetooth_BluetoothDevice.clazz,
897 android_bluetooth_BluetoothDevice.constructor,
898 addr_jstr.get(), (jint)addr_type);
899 }
900
prepareBluetoothLeBroadcastMetadataObject(JNIEnv * env,const bluetooth::le_audio::BroadcastMetadata & broadcast_metadata)901 jobject prepareBluetoothLeBroadcastMetadataObject(
902 JNIEnv* env,
903 const bluetooth::le_audio::BroadcastMetadata& broadcast_metadata) {
904 ScopedLocalRef<jobject> device_obj(
905 env, prepareBluetoothDeviceObject(env, broadcast_metadata.addr,
906 broadcast_metadata.addr_type));
907 if (!device_obj.get()) {
908 LOG(ERROR) << "Failed to create new BluetoothDevice";
909 return nullptr;
910 }
911
912 ScopedLocalRef<jobject> subgroup_list_obj(
913 env,
914 prepareLeBroadcastSubgroupListObject(
915 env, broadcast_metadata.basic_audio_announcement.subgroup_configs));
916 if (!subgroup_list_obj.get()) {
917 LOG(ERROR) << "Failed to create new Subgroup array";
918 return nullptr;
919 }
920
921 // Skip the leading null char bytes
922 int nativeCodeSize = 16;
923 int nativeCodeLeadingZeros = 0;
924 if (broadcast_metadata.broadcast_code) {
925 auto& nativeCode = broadcast_metadata.broadcast_code.value();
926 nativeCodeLeadingZeros =
927 std::find_if(nativeCode.cbegin(), nativeCode.cend(),
928 [](int x) { return x != 0x00; }) -
929 nativeCode.cbegin();
930 nativeCodeSize = nativeCode.size() - nativeCodeLeadingZeros;
931 }
932
933 ScopedLocalRef<jbyteArray> code(env, env->NewByteArray(nativeCodeSize));
934 if (!code.get()) {
935 LOG(ERROR) << "Failed to create new jbyteArray for the broadcast code";
936 return nullptr;
937 }
938
939 if (broadcast_metadata.broadcast_code) {
940 env->SetByteArrayRegion(
941 code.get(), 0, nativeCodeSize,
942 (const jbyte*)broadcast_metadata.broadcast_code->data() +
943 nativeCodeLeadingZeros);
944 CHECK(!env->ExceptionCheck());
945 }
946
947 ScopedLocalRef<jstring> broadcast_name(
948 env, env->NewStringUTF(broadcast_metadata.broadcast_name.c_str()));
949 if (!broadcast_name.get()) {
950 LOG(ERROR) << "Failed to create new broadcast name String";
951 return nullptr;
952 }
953
954 jint audio_cfg_quality = 0;
955 if (broadcast_metadata.public_announcement.features &
956 bluetooth::le_audio::kLeAudioQualityStandard) {
957 // Set bit 0 for AUDIO_CONFIG_QUALITY_STANDARD
958 audio_cfg_quality |= 0x1 << bluetooth::le_audio::QUALITY_STANDARD;
959 }
960 if (broadcast_metadata.public_announcement.features &
961 bluetooth::le_audio::kLeAudioQualityHigh) {
962 // Set bit 1 for AUDIO_CONFIG_QUALITY_HIGH
963 audio_cfg_quality |= 0x1 << bluetooth::le_audio::QUALITY_HIGH;
964 }
965
966 ScopedLocalRef<jobject> public_meta_obj(
967 env, prepareLeAudioContentMetadataObject(
968 env, broadcast_metadata.public_announcement.metadata));
969 if (!public_meta_obj.get()) {
970 LOG(ERROR) << "Failed to create new public metadata obj";
971 return nullptr;
972 }
973
974 return env->NewObject(
975 android_bluetooth_BluetoothLeBroadcastMetadata.clazz,
976 android_bluetooth_BluetoothLeBroadcastMetadata.constructor,
977 (jint)broadcast_metadata.addr_type, device_obj.get(),
978 (jint)broadcast_metadata.adv_sid, (jint)broadcast_metadata.broadcast_id,
979 (jint)broadcast_metadata.pa_interval,
980 broadcast_metadata.broadcast_code ? true : false,
981 broadcast_metadata.is_public, broadcast_name.get(),
982 broadcast_metadata.broadcast_code ? code.get() : nullptr,
983 (jint)broadcast_metadata.basic_audio_announcement.presentation_delay,
984 audio_cfg_quality, public_meta_obj.get(), subgroup_list_obj.get());
985 }
986
987 class LeAudioBroadcasterCallbacksImpl : public LeAudioBroadcasterCallbacks {
988 public:
989 ~LeAudioBroadcasterCallbacksImpl() = default;
990
OnBroadcastCreated(uint32_t broadcast_id,bool success)991 void OnBroadcastCreated(uint32_t broadcast_id, bool success) override {
992 LOG(INFO) << __func__;
993
994 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex);
995 CallbackEnv sCallbackEnv(__func__);
996
997 if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return;
998 sCallbackEnv->CallVoidMethod(sBroadcasterCallbacksObj,
999 method_onBroadcastCreated, (jint)broadcast_id,
1000 success ? JNI_TRUE : JNI_FALSE);
1001 }
1002
OnBroadcastDestroyed(uint32_t broadcast_id)1003 void OnBroadcastDestroyed(uint32_t broadcast_id) override {
1004 LOG(INFO) << __func__;
1005
1006 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex);
1007 CallbackEnv sCallbackEnv(__func__);
1008
1009 if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return;
1010 sCallbackEnv->CallVoidMethod(sBroadcasterCallbacksObj,
1011 method_onBroadcastDestroyed,
1012 (jint)broadcast_id);
1013 }
1014
OnBroadcastStateChanged(uint32_t broadcast_id,BroadcastState state)1015 void OnBroadcastStateChanged(uint32_t broadcast_id,
1016 BroadcastState state) override {
1017 LOG(INFO) << __func__;
1018
1019 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex);
1020 CallbackEnv sCallbackEnv(__func__);
1021
1022 if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return;
1023 sCallbackEnv->CallVoidMethod(
1024 sBroadcasterCallbacksObj, method_onBroadcastStateChanged,
1025 (jint)broadcast_id,
1026 (jint) static_cast<std::underlying_type<BroadcastState>::type>(state));
1027 }
1028
OnBroadcastMetadataChanged(uint32_t broadcast_id,const bluetooth::le_audio::BroadcastMetadata & broadcast_metadata)1029 void OnBroadcastMetadataChanged(uint32_t broadcast_id,
1030 const bluetooth::le_audio::BroadcastMetadata&
1031 broadcast_metadata) override {
1032 LOG(INFO) << __func__;
1033
1034 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterCallbacksMutex);
1035 CallbackEnv sCallbackEnv(__func__);
1036
1037 ScopedLocalRef<jobject> metadata_obj(
1038 sCallbackEnv.get(), prepareBluetoothLeBroadcastMetadataObject(
1039 sCallbackEnv.get(), broadcast_metadata));
1040
1041 if (!sCallbackEnv.valid() || sBroadcasterCallbacksObj == nullptr) return;
1042 sCallbackEnv->CallVoidMethod(sBroadcasterCallbacksObj,
1043 method_onBroadcastMetadataChanged,
1044 (jint)broadcast_id, metadata_obj.get());
1045 }
1046 };
1047
1048 static LeAudioBroadcasterCallbacksImpl sLeAudioBroadcasterCallbacks;
1049
BroadcasterClassInitNative(JNIEnv * env,jclass clazz)1050 static void BroadcasterClassInitNative(JNIEnv* env, jclass clazz) {
1051 method_onBroadcastCreated =
1052 env->GetMethodID(clazz, "onBroadcastCreated", "(IZ)V");
1053 method_onBroadcastDestroyed =
1054 env->GetMethodID(clazz, "onBroadcastDestroyed", "(I)V");
1055 method_onBroadcastStateChanged =
1056 env->GetMethodID(clazz, "onBroadcastStateChanged", "(II)V");
1057 method_onBroadcastMetadataChanged =
1058 env->GetMethodID(clazz, "onBroadcastMetadataChanged",
1059 "(ILandroid/bluetooth/BluetoothLeBroadcastMetadata;)V");
1060
1061 jclass jniArrayListClass = env->FindClass("java/util/ArrayList");
1062 java_util_ArrayList.constructor =
1063 env->GetMethodID(jniArrayListClass, "<init>", "()V");
1064 java_util_ArrayList.add =
1065 env->GetMethodID(jniArrayListClass, "add", "(Ljava/lang/Object;)Z");
1066
1067 jclass jniBluetoothLeAudioCodecConfigMetadataClass =
1068 env->FindClass("android/bluetooth/BluetoothLeAudioCodecConfigMetadata");
1069 android_bluetooth_BluetoothLeAudioCodecConfigMetadata.constructor =
1070 env->GetMethodID(jniBluetoothLeAudioCodecConfigMetadataClass, "<init>",
1071 "(JIII[B)V");
1072
1073 jclass jniBluetoothLeAudioContentMetadataClass =
1074 env->FindClass("android/bluetooth/BluetoothLeAudioContentMetadata");
1075 android_bluetooth_BluetoothLeAudioContentMetadata.constructor =
1076 env->GetMethodID(jniBluetoothLeAudioContentMetadataClass, "<init>",
1077 "(Ljava/lang/String;Ljava/lang/String;[B)V");
1078
1079 jclass jniBluetoothLeBroadcastChannelClass =
1080 env->FindClass("android/bluetooth/BluetoothLeBroadcastChannel");
1081 android_bluetooth_BluetoothLeBroadcastChannel.constructor = env->GetMethodID(
1082 jniBluetoothLeBroadcastChannelClass, "<init>",
1083 "(ZILandroid/bluetooth/BluetoothLeAudioCodecConfigMetadata;)V");
1084
1085 jclass jniBluetoothLeBroadcastSubgroupClass =
1086 env->FindClass("android/bluetooth/BluetoothLeBroadcastSubgroup");
1087 android_bluetooth_BluetoothLeBroadcastSubgroup.constructor = env->GetMethodID(
1088 jniBluetoothLeBroadcastSubgroupClass, "<init>",
1089 "(JLandroid/bluetooth/BluetoothLeAudioCodecConfigMetadata;"
1090 "Landroid/bluetooth/BluetoothLeAudioContentMetadata;"
1091 "Ljava/util/List;)V");
1092
1093 jclass jniBluetoothDeviceClass =
1094 env->FindClass("android/bluetooth/BluetoothDevice");
1095 android_bluetooth_BluetoothDevice.constructor = env->GetMethodID(
1096 jniBluetoothDeviceClass, "<init>", "(Ljava/lang/String;I)V");
1097
1098 jclass jniBluetoothLeBroadcastMetadataClass =
1099 env->FindClass("android/bluetooth/BluetoothLeBroadcastMetadata");
1100 android_bluetooth_BluetoothLeBroadcastMetadata.constructor = env->GetMethodID(
1101 jniBluetoothLeBroadcastMetadataClass, "<init>",
1102 "(ILandroid/bluetooth/BluetoothDevice;IIIZZLjava/lang/String;"
1103 "[BIILandroid/bluetooth/BluetoothLeAudioContentMetadata;"
1104 "Ljava/util/List;)V");
1105 }
1106
BroadcasterInitNative(JNIEnv * env,jobject object)1107 static void BroadcasterInitNative(JNIEnv* env, jobject object) {
1108 std::unique_lock<std::shared_timed_mutex> interface_lock(
1109 sBroadcasterInterfaceMutex);
1110 std::unique_lock<std::shared_timed_mutex> callbacks_lock(
1111 sBroadcasterCallbacksMutex);
1112
1113 const bt_interface_t* btInf = getBluetoothInterface();
1114 if (btInf == nullptr) {
1115 LOG(ERROR) << "Bluetooth module is not loaded";
1116 return;
1117 }
1118
1119 android_bluetooth_BluetoothDevice.clazz = (jclass)env->NewGlobalRef(
1120 env->FindClass("android/bluetooth/BluetoothDevice"));
1121 if (android_bluetooth_BluetoothDevice.clazz == nullptr) {
1122 LOG(ERROR) << "Failed to allocate Global Ref for BluetoothDevice class";
1123 return;
1124 }
1125
1126 java_util_ArrayList.clazz =
1127 (jclass)env->NewGlobalRef(env->FindClass("java/util/ArrayList"));
1128 if (java_util_ArrayList.clazz == nullptr) {
1129 LOG(ERROR) << "Failed to allocate Global Ref for ArrayList class";
1130 return;
1131 }
1132
1133 android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz =
1134 (jclass)env->NewGlobalRef(env->FindClass(
1135 "android/bluetooth/BluetoothLeAudioCodecConfigMetadata"));
1136 if (android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz == nullptr) {
1137 LOG(ERROR) << "Failed to allocate Global Ref for "
1138 "BluetoothLeAudioCodecConfigMetadata class";
1139 return;
1140 }
1141
1142 android_bluetooth_BluetoothLeAudioContentMetadata.clazz =
1143 (jclass)env->NewGlobalRef(
1144 env->FindClass("android/bluetooth/BluetoothLeAudioContentMetadata"));
1145 if (android_bluetooth_BluetoothLeAudioContentMetadata.clazz == nullptr) {
1146 LOG(ERROR) << "Failed to allocate Global Ref for "
1147 "BluetoothLeAudioContentMetadata class";
1148 return;
1149 }
1150
1151 android_bluetooth_BluetoothLeBroadcastSubgroup.clazz =
1152 (jclass)env->NewGlobalRef(
1153 env->FindClass("android/bluetooth/BluetoothLeBroadcastSubgroup"));
1154 if (android_bluetooth_BluetoothLeBroadcastSubgroup.clazz == nullptr) {
1155 LOG(ERROR) << "Failed to allocate Global Ref for "
1156 "BluetoothLeBroadcastSubgroup class";
1157 return;
1158 }
1159
1160 android_bluetooth_BluetoothLeBroadcastChannel.clazz =
1161 (jclass)env->NewGlobalRef(
1162 env->FindClass("android/bluetooth/BluetoothLeBroadcastChannel"));
1163 if (android_bluetooth_BluetoothLeBroadcastChannel.clazz == nullptr) {
1164 LOG(ERROR) << "Failed to allocate Global Ref for "
1165 "BluetoothLeBroadcastChannel class";
1166 return;
1167 }
1168
1169 android_bluetooth_BluetoothLeBroadcastMetadata.clazz =
1170 (jclass)env->NewGlobalRef(
1171 env->FindClass("android/bluetooth/BluetoothLeBroadcastMetadata"));
1172 if (android_bluetooth_BluetoothLeBroadcastMetadata.clazz == nullptr) {
1173 LOG(ERROR) << "Failed to allocate Global Ref for "
1174 "BluetoothLeBroadcastMetadata class";
1175 return;
1176 }
1177
1178 if (sBroadcasterCallbacksObj != nullptr) {
1179 LOG(INFO) << "Cleaning up LeAudio Broadcaster callback object";
1180 env->DeleteGlobalRef(sBroadcasterCallbacksObj);
1181 sBroadcasterCallbacksObj = nullptr;
1182 }
1183
1184 if ((sBroadcasterCallbacksObj = env->NewGlobalRef(object)) == nullptr) {
1185 LOG(ERROR)
1186 << "Failed to allocate Global Ref for LeAudio Broadcaster Callbacks";
1187 return;
1188 }
1189
1190 sLeAudioBroadcasterInterface =
1191 (LeAudioBroadcasterInterface*)btInf->get_profile_interface(
1192 BT_PROFILE_LE_AUDIO_BROADCASTER_ID);
1193 if (sLeAudioBroadcasterInterface == nullptr) {
1194 LOG(ERROR) << "Failed to get Bluetooth LeAudio Broadcaster Interface";
1195 return;
1196 }
1197
1198 sLeAudioBroadcasterInterface->Initialize(&sLeAudioBroadcasterCallbacks);
1199 }
1200
BroadcasterStopNative(JNIEnv * env,jobject object)1201 static void BroadcasterStopNative(JNIEnv* env, jobject object) {
1202 std::unique_lock<std::shared_timed_mutex> interface_lock(
1203 sBroadcasterInterfaceMutex);
1204
1205 const bt_interface_t* btInf = getBluetoothInterface();
1206 if (btInf == nullptr) {
1207 LOG(ERROR) << "Bluetooth module is not loaded";
1208 return;
1209 }
1210
1211 if (sLeAudioBroadcasterInterface != nullptr)
1212 sLeAudioBroadcasterInterface->Stop();
1213 }
1214
BroadcasterCleanupNative(JNIEnv * env,jobject object)1215 static void BroadcasterCleanupNative(JNIEnv* env, jobject object) {
1216 std::unique_lock<std::shared_timed_mutex> interface_lock(
1217 sBroadcasterInterfaceMutex);
1218 std::unique_lock<std::shared_timed_mutex> callbacks_lock(
1219 sBroadcasterCallbacksMutex);
1220
1221 const bt_interface_t* btInf = getBluetoothInterface();
1222 if (btInf == nullptr) {
1223 LOG(ERROR) << "Bluetooth module is not loaded";
1224 return;
1225 }
1226
1227 env->DeleteGlobalRef(java_util_ArrayList.clazz);
1228 java_util_ArrayList.clazz = nullptr;
1229
1230 env->DeleteGlobalRef(android_bluetooth_BluetoothDevice.clazz);
1231 android_bluetooth_BluetoothDevice.clazz = nullptr;
1232
1233 env->DeleteGlobalRef(
1234 android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz);
1235 android_bluetooth_BluetoothLeAudioCodecConfigMetadata.clazz = nullptr;
1236
1237 env->DeleteGlobalRef(android_bluetooth_BluetoothLeAudioContentMetadata.clazz);
1238 android_bluetooth_BluetoothLeAudioContentMetadata.clazz = nullptr;
1239
1240 env->DeleteGlobalRef(android_bluetooth_BluetoothLeBroadcastSubgroup.clazz);
1241 android_bluetooth_BluetoothLeBroadcastSubgroup.clazz = nullptr;
1242
1243 env->DeleteGlobalRef(android_bluetooth_BluetoothLeBroadcastChannel.clazz);
1244 android_bluetooth_BluetoothLeBroadcastChannel.clazz = nullptr;
1245
1246 env->DeleteGlobalRef(android_bluetooth_BluetoothLeBroadcastMetadata.clazz);
1247 android_bluetooth_BluetoothLeBroadcastMetadata.clazz = nullptr;
1248
1249 if (sLeAudioBroadcasterInterface != nullptr) {
1250 sLeAudioBroadcasterInterface->Cleanup();
1251 sLeAudioBroadcasterInterface = nullptr;
1252 }
1253
1254 if (sBroadcasterCallbacksObj != nullptr) {
1255 env->DeleteGlobalRef(sBroadcasterCallbacksObj);
1256 sBroadcasterCallbacksObj = nullptr;
1257 }
1258 }
1259
convertToDataVectors(JNIEnv * env,jobjectArray dataArray)1260 std::vector<std::vector<uint8_t>> convertToDataVectors(JNIEnv* env,
1261 jobjectArray dataArray) {
1262 jsize arraySize = env->GetArrayLength(dataArray);
1263 std::vector<std::vector<uint8_t>> res(arraySize);
1264
1265 for (int i = 0; i < arraySize; ++i) {
1266 jbyteArray rowData = (jbyteArray)env->GetObjectArrayElement(dataArray, i);
1267 jsize dataSize = env->GetArrayLength(rowData);
1268 std::vector<uint8_t>& rowVector = res[i];
1269 rowVector.resize(dataSize);
1270 env->GetByteArrayRegion(rowData, 0, dataSize,
1271 reinterpret_cast<jbyte*>(rowVector.data()));
1272 env->DeleteLocalRef(rowData);
1273 }
1274 return res;
1275 }
1276
CreateBroadcastNative(JNIEnv * env,jobject object,jboolean isPublic,jstring broadcastName,jbyteArray broadcast_code,jbyteArray publicMetadata,jintArray qualityArray,jobjectArray metadataArray)1277 static void CreateBroadcastNative(JNIEnv* env, jobject object,
1278 jboolean isPublic, jstring broadcastName,
1279 jbyteArray broadcast_code,
1280 jbyteArray publicMetadata,
1281 jintArray qualityArray,
1282 jobjectArray metadataArray) {
1283 LOG(INFO) << __func__;
1284 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1285 if (!sLeAudioBroadcasterInterface) return;
1286
1287 std::array<uint8_t, 16> code_array{0};
1288 if (broadcast_code) {
1289 jsize size = env->GetArrayLength(broadcast_code);
1290 if (size > 16) {
1291 ALOGE("%s: broadcast code to long", __func__);
1292 return;
1293 }
1294
1295 // Padding with zeros on MSB positions if code is shorter than 16 octets
1296 env->GetByteArrayRegion(broadcast_code, 0, size, (jbyte*)code_array.data());
1297 }
1298
1299 const char* broadcast_name = nullptr;
1300 if (broadcastName) {
1301 broadcast_name = env->GetStringUTFChars(broadcastName, nullptr);
1302 }
1303
1304 jbyte* public_meta = nullptr;
1305 if (publicMetadata) {
1306 public_meta = env->GetByteArrayElements(publicMetadata, nullptr);
1307 }
1308
1309 jint* quality_array = nullptr;
1310 if (qualityArray) {
1311 quality_array = env->GetIntArrayElements(qualityArray, nullptr);
1312 }
1313
1314 sLeAudioBroadcasterInterface->CreateBroadcast(
1315 isPublic, broadcast_name ? broadcast_name : "",
1316 broadcast_code ? std::optional<std::array<uint8_t, 16>>(code_array)
1317 : std::nullopt,
1318 public_meta ? std::vector<uint8_t>(
1319 public_meta, public_meta + env->GetArrayLength(publicMetadata))
1320 : std::vector<uint8_t>(),
1321 quality_array ? std::vector<uint8_t>(
1322 quality_array, quality_array + env->GetArrayLength(qualityArray))
1323 : std::vector<uint8_t>(),
1324 convertToDataVectors(env, metadataArray));
1325
1326 if (broadcast_name) env->ReleaseStringUTFChars(broadcastName, broadcast_name);
1327 if (public_meta) env->ReleaseByteArrayElements(publicMetadata, public_meta, 0);
1328 if (quality_array) env->ReleaseIntArrayElements(qualityArray, quality_array, 0);
1329 }
1330
UpdateMetadataNative(JNIEnv * env,jobject object,jint broadcast_id,jstring broadcastName,jbyteArray publicMetadata,jobjectArray metadataArray)1331 static void UpdateMetadataNative(JNIEnv* env, jobject object, jint broadcast_id,
1332 jstring broadcastName,
1333 jbyteArray publicMetadata,
1334 jobjectArray metadataArray) {
1335 const char* broadcast_name = nullptr;
1336 if (broadcastName) {
1337 broadcast_name = env->GetStringUTFChars(broadcastName, nullptr);
1338 }
1339
1340 jbyte* public_meta = nullptr;
1341 if (publicMetadata) {
1342 public_meta = env->GetByteArrayElements(publicMetadata, nullptr);
1343 }
1344
1345 sLeAudioBroadcasterInterface->UpdateMetadata(
1346 broadcast_id, broadcast_name ? broadcast_name : "",
1347 public_meta
1348 ? std::vector<uint8_t>(
1349 public_meta, public_meta + env->GetArrayLength(publicMetadata))
1350 : std::vector<uint8_t>(),
1351 convertToDataVectors(env, metadataArray));
1352
1353 if (broadcast_name) env->ReleaseStringUTFChars(broadcastName, broadcast_name);
1354 if (public_meta) env->ReleaseByteArrayElements(publicMetadata, public_meta, 0);
1355 }
1356
StartBroadcastNative(JNIEnv * env,jobject object,jint broadcast_id)1357 static void StartBroadcastNative(JNIEnv* env, jobject object,
1358 jint broadcast_id) {
1359 LOG(INFO) << __func__;
1360 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1361 if (!sLeAudioBroadcasterInterface) return;
1362 sLeAudioBroadcasterInterface->StartBroadcast(broadcast_id);
1363 }
1364
StopBroadcastNative(JNIEnv * env,jobject object,jint broadcast_id)1365 static void StopBroadcastNative(JNIEnv* env, jobject object,
1366 jint broadcast_id) {
1367 LOG(INFO) << __func__;
1368 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1369 if (!sLeAudioBroadcasterInterface) return;
1370 sLeAudioBroadcasterInterface->StopBroadcast(broadcast_id);
1371 }
1372
PauseBroadcastNative(JNIEnv * env,jobject object,jint broadcast_id)1373 static void PauseBroadcastNative(JNIEnv* env, jobject object,
1374 jint broadcast_id) {
1375 LOG(INFO) << __func__;
1376 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1377 if (!sLeAudioBroadcasterInterface) return;
1378 sLeAudioBroadcasterInterface->PauseBroadcast(broadcast_id);
1379 }
1380
DestroyBroadcastNative(JNIEnv * env,jobject object,jint broadcast_id)1381 static void DestroyBroadcastNative(JNIEnv* env, jobject object,
1382 jint broadcast_id) {
1383 LOG(INFO) << __func__;
1384 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1385 if (!sLeAudioBroadcasterInterface) return;
1386 sLeAudioBroadcasterInterface->DestroyBroadcast(broadcast_id);
1387 }
1388
getBroadcastMetadataNative(JNIEnv * env,jobject object,jint broadcast_id)1389 static void getBroadcastMetadataNative(JNIEnv* env, jobject object,
1390 jint broadcast_id) {
1391 LOG(INFO) << __func__;
1392 std::shared_lock<std::shared_timed_mutex> lock(sBroadcasterInterfaceMutex);
1393 if (!sLeAudioBroadcasterInterface) return;
1394 sLeAudioBroadcasterInterface->GetBroadcastMetadata(broadcast_id);
1395 }
1396
1397 static JNINativeMethod sBroadcasterMethods[] = {
1398 {"classInitNative", "()V", (void*)BroadcasterClassInitNative},
1399 {"initNative", "()V", (void*)BroadcasterInitNative},
1400 {"stopNative", "()V", (void*)BroadcasterStopNative},
1401 {"cleanupNative", "()V", (void*)BroadcasterCleanupNative},
1402 {"createBroadcastNative", "(ZLjava/lang/String;[B[B[I[[B)V",
1403 (void*)CreateBroadcastNative},
1404 {"updateMetadataNative", "(ILjava/lang/String;[B[[B)V",
1405 (void*)UpdateMetadataNative},
1406 {"startBroadcastNative", "(I)V", (void*)StartBroadcastNative},
1407 {"stopBroadcastNative", "(I)V", (void*)StopBroadcastNative},
1408 {"pauseBroadcastNative", "(I)V", (void*)PauseBroadcastNative},
1409 {"destroyBroadcastNative", "(I)V", (void*)DestroyBroadcastNative},
1410 {"getBroadcastMetadataNative", "(I)V", (void*)getBroadcastMetadataNative},
1411 };
1412
register_com_android_bluetooth_le_audio(JNIEnv * env)1413 int register_com_android_bluetooth_le_audio(JNIEnv* env) {
1414 int register_success = jniRegisterNativeMethods(
1415 env, "com/android/bluetooth/le_audio/LeAudioNativeInterface", sMethods,
1416 NELEM(sMethods));
1417 return register_success &
1418 jniRegisterNativeMethods(
1419 env,
1420 "com/android/bluetooth/le_audio/LeAudioBroadcasterNativeInterface",
1421 sBroadcasterMethods, NELEM(sBroadcasterMethods));
1422 }
1423 } // namespace android
1424