1 /*
2 * Copyright (C) 2012 The Android Open Source Project
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 "BluetoothA2dpServiceJni"
18
19 #define LOG_NDEBUG 0
20
21 #include "com_android_bluetooth.h"
22 #include "hardware/bt_av.h"
23 #include "utils/Log.h"
24
25 #include <string.h>
26 #include <shared_mutex>
27
28 namespace android {
29 static jmethodID method_onConnectionStateChanged;
30 static jmethodID method_onAudioStateChanged;
31 static jmethodID method_onCodecConfigChanged;
32 static jmethodID method_isMandatoryCodecPreferred;
33
34 static struct {
35 jclass clazz;
36 jmethodID constructor;
37 jmethodID getCodecType;
38 jmethodID getCodecPriority;
39 jmethodID getSampleRate;
40 jmethodID getBitsPerSample;
41 jmethodID getChannelMode;
42 jmethodID getCodecSpecific1;
43 jmethodID getCodecSpecific2;
44 jmethodID getCodecSpecific3;
45 jmethodID getCodecSpecific4;
46 } android_bluetooth_BluetoothCodecConfig;
47
48 static const btav_source_interface_t* sBluetoothA2dpInterface = nullptr;
49 static std::shared_timed_mutex interface_mutex;
50
51 static jobject mCallbacksObj = nullptr;
52 static std::shared_timed_mutex callbacks_mutex;
53
bta2dp_connection_state_callback(const RawAddress & bd_addr,btav_connection_state_t state)54 static void bta2dp_connection_state_callback(const RawAddress& bd_addr,
55 btav_connection_state_t state) {
56 ALOGI("%s", __func__);
57
58 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
59 CallbackEnv sCallbackEnv(__func__);
60 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
61
62 ScopedLocalRef<jbyteArray> addr(
63 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
64 if (!addr.get()) {
65 ALOGE("%s: Fail to new jbyteArray bd addr", __func__);
66 return;
67 }
68
69 sCallbackEnv->SetByteArrayRegion(
70 addr.get(), 0, sizeof(RawAddress),
71 reinterpret_cast<const jbyte*>(bd_addr.address));
72 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged,
73 addr.get(), (jint)state);
74 }
75
bta2dp_audio_state_callback(const RawAddress & bd_addr,btav_audio_state_t state)76 static void bta2dp_audio_state_callback(const RawAddress& bd_addr,
77 btav_audio_state_t state) {
78 ALOGI("%s", __func__);
79
80 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
81 CallbackEnv sCallbackEnv(__func__);
82 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
83
84 ScopedLocalRef<jbyteArray> addr(
85 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
86 if (!addr.get()) {
87 ALOGE("%s: Fail to new jbyteArray bd addr", __func__);
88 return;
89 }
90
91 sCallbackEnv->SetByteArrayRegion(
92 addr.get(), 0, sizeof(RawAddress),
93 reinterpret_cast<const jbyte*>(bd_addr.address));
94 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged,
95 addr.get(), (jint)state);
96 }
97
bta2dp_audio_config_callback(const RawAddress & bd_addr,btav_a2dp_codec_config_t codec_config,std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities,std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities)98 static void bta2dp_audio_config_callback(
99 const RawAddress& bd_addr, btav_a2dp_codec_config_t codec_config,
100 std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities,
101 std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities) {
102 ALOGI("%s", __func__);
103
104 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
105 CallbackEnv sCallbackEnv(__func__);
106 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
107
108 jobject codecConfigObj = sCallbackEnv->NewObject(
109 android_bluetooth_BluetoothCodecConfig.clazz,
110 android_bluetooth_BluetoothCodecConfig.constructor,
111 (jint)codec_config.codec_type, (jint)codec_config.codec_priority,
112 (jint)codec_config.sample_rate, (jint)codec_config.bits_per_sample,
113 (jint)codec_config.channel_mode, (jlong)codec_config.codec_specific_1,
114 (jlong)codec_config.codec_specific_2,
115 (jlong)codec_config.codec_specific_3,
116 (jlong)codec_config.codec_specific_4);
117
118 jsize i = 0;
119 jobjectArray local_capabilities_array = sCallbackEnv->NewObjectArray(
120 (jsize)codecs_local_capabilities.size(),
121 android_bluetooth_BluetoothCodecConfig.clazz, nullptr);
122 for (auto const& cap : codecs_local_capabilities) {
123 jobject capObj = sCallbackEnv->NewObject(
124 android_bluetooth_BluetoothCodecConfig.clazz,
125 android_bluetooth_BluetoothCodecConfig.constructor,
126 (jint)cap.codec_type, (jint)cap.codec_priority, (jint)cap.sample_rate,
127 (jint)cap.bits_per_sample, (jint)cap.channel_mode,
128 (jlong)cap.codec_specific_1, (jlong)cap.codec_specific_2,
129 (jlong)cap.codec_specific_3, (jlong)cap.codec_specific_4);
130 sCallbackEnv->SetObjectArrayElement(local_capabilities_array, i++, capObj);
131 sCallbackEnv->DeleteLocalRef(capObj);
132 }
133
134 i = 0;
135 jobjectArray selectable_capabilities_array = sCallbackEnv->NewObjectArray(
136 (jsize)codecs_selectable_capabilities.size(),
137 android_bluetooth_BluetoothCodecConfig.clazz, nullptr);
138 for (auto const& cap : codecs_selectable_capabilities) {
139 jobject capObj = sCallbackEnv->NewObject(
140 android_bluetooth_BluetoothCodecConfig.clazz,
141 android_bluetooth_BluetoothCodecConfig.constructor,
142 (jint)cap.codec_type, (jint)cap.codec_priority, (jint)cap.sample_rate,
143 (jint)cap.bits_per_sample, (jint)cap.channel_mode,
144 (jlong)cap.codec_specific_1, (jlong)cap.codec_specific_2,
145 (jlong)cap.codec_specific_3, (jlong)cap.codec_specific_4);
146 sCallbackEnv->SetObjectArrayElement(selectable_capabilities_array, i++,
147 capObj);
148 sCallbackEnv->DeleteLocalRef(capObj);
149 }
150
151 ScopedLocalRef<jbyteArray> addr(
152 sCallbackEnv.get(), sCallbackEnv->NewByteArray(RawAddress::kLength));
153 if (!addr.get()) {
154 ALOGE("%s: Fail to new jbyteArray bd addr", __func__);
155 return;
156 }
157 sCallbackEnv->SetByteArrayRegion(
158 addr.get(), 0, RawAddress::kLength,
159 reinterpret_cast<const jbyte*>(bd_addr.address));
160
161 sCallbackEnv->CallVoidMethod(
162 mCallbacksObj, method_onCodecConfigChanged, addr.get(), codecConfigObj,
163 local_capabilities_array, selectable_capabilities_array);
164 }
165
bta2dp_mandatory_codec_preferred_callback(const RawAddress & bd_addr)166 static bool bta2dp_mandatory_codec_preferred_callback(
167 const RawAddress& bd_addr) {
168 ALOGI("%s", __func__);
169
170 std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
171 CallbackEnv sCallbackEnv(__func__);
172 if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return false;
173
174 ScopedLocalRef<jbyteArray> addr(
175 sCallbackEnv.get(), sCallbackEnv->NewByteArray(RawAddress::kLength));
176 if (!addr.get()) {
177 ALOGE("%s: Fail to new jbyteArray bd addr", __func__);
178 return false;
179 }
180 sCallbackEnv->SetByteArrayRegion(
181 addr.get(), 0, RawAddress::kLength,
182 reinterpret_cast<const jbyte*>(bd_addr.address));
183 return sCallbackEnv->CallBooleanMethod(
184 mCallbacksObj, method_isMandatoryCodecPreferred, addr.get());
185 }
186
187 static btav_source_callbacks_t sBluetoothA2dpCallbacks = {
188 sizeof(sBluetoothA2dpCallbacks),
189 bta2dp_connection_state_callback,
190 bta2dp_audio_state_callback,
191 bta2dp_audio_config_callback,
192 bta2dp_mandatory_codec_preferred_callback,
193 };
194
classInitNative(JNIEnv * env,jclass clazz)195 static void classInitNative(JNIEnv* env, jclass clazz) {
196 jclass jniBluetoothCodecConfigClass =
197 env->FindClass("android/bluetooth/BluetoothCodecConfig");
198 android_bluetooth_BluetoothCodecConfig.constructor =
199 env->GetMethodID(jniBluetoothCodecConfigClass, "<init>", "(IIIIIJJJJ)V");
200 android_bluetooth_BluetoothCodecConfig.getCodecType =
201 env->GetMethodID(jniBluetoothCodecConfigClass, "getCodecType", "()I");
202 android_bluetooth_BluetoothCodecConfig.getCodecPriority =
203 env->GetMethodID(jniBluetoothCodecConfigClass, "getCodecPriority", "()I");
204 android_bluetooth_BluetoothCodecConfig.getSampleRate =
205 env->GetMethodID(jniBluetoothCodecConfigClass, "getSampleRate", "()I");
206 android_bluetooth_BluetoothCodecConfig.getBitsPerSample =
207 env->GetMethodID(jniBluetoothCodecConfigClass, "getBitsPerSample", "()I");
208 android_bluetooth_BluetoothCodecConfig.getChannelMode =
209 env->GetMethodID(jniBluetoothCodecConfigClass, "getChannelMode", "()I");
210 android_bluetooth_BluetoothCodecConfig.getCodecSpecific1 = env->GetMethodID(
211 jniBluetoothCodecConfigClass, "getCodecSpecific1", "()J");
212 android_bluetooth_BluetoothCodecConfig.getCodecSpecific2 = env->GetMethodID(
213 jniBluetoothCodecConfigClass, "getCodecSpecific2", "()J");
214 android_bluetooth_BluetoothCodecConfig.getCodecSpecific3 = env->GetMethodID(
215 jniBluetoothCodecConfigClass, "getCodecSpecific3", "()J");
216 android_bluetooth_BluetoothCodecConfig.getCodecSpecific4 = env->GetMethodID(
217 jniBluetoothCodecConfigClass, "getCodecSpecific4", "()J");
218
219 method_onConnectionStateChanged =
220 env->GetMethodID(clazz, "onConnectionStateChanged", "([BI)V");
221
222 method_onAudioStateChanged =
223 env->GetMethodID(clazz, "onAudioStateChanged", "([BI)V");
224
225 method_onCodecConfigChanged =
226 env->GetMethodID(clazz, "onCodecConfigChanged",
227 "([BLandroid/bluetooth/BluetoothCodecConfig;"
228 "[Landroid/bluetooth/BluetoothCodecConfig;"
229 "[Landroid/bluetooth/BluetoothCodecConfig;)V");
230
231 method_isMandatoryCodecPreferred =
232 env->GetMethodID(clazz, "isMandatoryCodecPreferred", "([B)Z");
233
234 ALOGI("%s: succeeds", __func__);
235 }
236
prepareCodecPreferences(JNIEnv * env,jobject object,jobjectArray codecConfigArray)237 static std::vector<btav_a2dp_codec_config_t> prepareCodecPreferences(
238 JNIEnv* env, jobject object, jobjectArray codecConfigArray) {
239 std::vector<btav_a2dp_codec_config_t> codec_preferences;
240
241 int numConfigs = env->GetArrayLength(codecConfigArray);
242 for (int i = 0; i < numConfigs; i++) {
243 jobject jcodecConfig = env->GetObjectArrayElement(codecConfigArray, i);
244 if (jcodecConfig == nullptr) continue;
245 if (!env->IsInstanceOf(jcodecConfig,
246 android_bluetooth_BluetoothCodecConfig.clazz)) {
247 ALOGE("%s: Invalid BluetoothCodecConfig instance", __func__);
248 continue;
249 }
250 jint codecType = env->CallIntMethod(
251 jcodecConfig, android_bluetooth_BluetoothCodecConfig.getCodecType);
252 jint codecPriority = env->CallIntMethod(
253 jcodecConfig, android_bluetooth_BluetoothCodecConfig.getCodecPriority);
254 jint sampleRate = env->CallIntMethod(
255 jcodecConfig, android_bluetooth_BluetoothCodecConfig.getSampleRate);
256 jint bitsPerSample = env->CallIntMethod(
257 jcodecConfig, android_bluetooth_BluetoothCodecConfig.getBitsPerSample);
258 jint channelMode = env->CallIntMethod(
259 jcodecConfig, android_bluetooth_BluetoothCodecConfig.getChannelMode);
260 jlong codecSpecific1 = env->CallLongMethod(
261 jcodecConfig, android_bluetooth_BluetoothCodecConfig.getCodecSpecific1);
262 jlong codecSpecific2 = env->CallLongMethod(
263 jcodecConfig, android_bluetooth_BluetoothCodecConfig.getCodecSpecific2);
264 jlong codecSpecific3 = env->CallLongMethod(
265 jcodecConfig, android_bluetooth_BluetoothCodecConfig.getCodecSpecific3);
266 jlong codecSpecific4 = env->CallLongMethod(
267 jcodecConfig, android_bluetooth_BluetoothCodecConfig.getCodecSpecific4);
268
269 btav_a2dp_codec_config_t codec_config = {
270 .codec_type = static_cast<btav_a2dp_codec_index_t>(codecType),
271 .codec_priority =
272 static_cast<btav_a2dp_codec_priority_t>(codecPriority),
273 .sample_rate = static_cast<btav_a2dp_codec_sample_rate_t>(sampleRate),
274 .bits_per_sample =
275 static_cast<btav_a2dp_codec_bits_per_sample_t>(bitsPerSample),
276 .channel_mode =
277 static_cast<btav_a2dp_codec_channel_mode_t>(channelMode),
278 .codec_specific_1 = codecSpecific1,
279 .codec_specific_2 = codecSpecific2,
280 .codec_specific_3 = codecSpecific3,
281 .codec_specific_4 = codecSpecific4};
282
283 codec_preferences.push_back(codec_config);
284 }
285 return codec_preferences;
286 }
287
initNative(JNIEnv * env,jobject object,jint maxConnectedAudioDevices,jobjectArray codecConfigArray,jobjectArray codecOffloadingArray)288 static void initNative(JNIEnv* env, jobject object,
289 jint maxConnectedAudioDevices,
290 jobjectArray codecConfigArray,
291 jobjectArray codecOffloadingArray) {
292 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
293 std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
294
295 const bt_interface_t* btInf = getBluetoothInterface();
296 if (btInf == nullptr) {
297 ALOGE("%s: Bluetooth module is not loaded", __func__);
298 return;
299 }
300
301 if (sBluetoothA2dpInterface != nullptr) {
302 ALOGW("%s: Cleaning up A2DP Interface before initializing...", __func__);
303 sBluetoothA2dpInterface->cleanup();
304 sBluetoothA2dpInterface = nullptr;
305 }
306
307 if (mCallbacksObj != nullptr) {
308 ALOGW("%s: Cleaning up A2DP callback object", __func__);
309 env->DeleteGlobalRef(mCallbacksObj);
310 mCallbacksObj = nullptr;
311 }
312
313 if ((mCallbacksObj = env->NewGlobalRef(object)) == nullptr) {
314 ALOGE("%s: Failed to allocate Global Ref for A2DP Callbacks", __func__);
315 return;
316 }
317
318 android_bluetooth_BluetoothCodecConfig.clazz = (jclass)env->NewGlobalRef(
319 env->FindClass("android/bluetooth/BluetoothCodecConfig"));
320 if (android_bluetooth_BluetoothCodecConfig.clazz == nullptr) {
321 ALOGE("%s: Failed to allocate Global Ref for BluetoothCodecConfig class",
322 __func__);
323 return;
324 }
325
326 sBluetoothA2dpInterface =
327 (btav_source_interface_t*)btInf->get_profile_interface(
328 BT_PROFILE_ADVANCED_AUDIO_ID);
329 if (sBluetoothA2dpInterface == nullptr) {
330 ALOGE("%s: Failed to get Bluetooth A2DP Interface", __func__);
331 return;
332 }
333
334 std::vector<btav_a2dp_codec_config_t> codec_priorities =
335 prepareCodecPreferences(env, object, codecConfigArray);
336
337 std::vector<btav_a2dp_codec_config_t> codec_offloading =
338 prepareCodecPreferences(env, object, codecOffloadingArray);
339
340 bt_status_t status = sBluetoothA2dpInterface->init(
341 &sBluetoothA2dpCallbacks, maxConnectedAudioDevices, codec_priorities,
342 codec_offloading);
343 if (status != BT_STATUS_SUCCESS) {
344 ALOGE("%s: Failed to initialize Bluetooth A2DP, status: %d", __func__,
345 status);
346 sBluetoothA2dpInterface = nullptr;
347 return;
348 }
349 }
350
cleanupNative(JNIEnv * env,jobject object)351 static void cleanupNative(JNIEnv* env, jobject object) {
352 std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
353 std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
354
355 const bt_interface_t* btInf = getBluetoothInterface();
356 if (btInf == nullptr) {
357 ALOGE("%s: Bluetooth module is not loaded", __func__);
358 return;
359 }
360
361 if (sBluetoothA2dpInterface != nullptr) {
362 sBluetoothA2dpInterface->cleanup();
363 sBluetoothA2dpInterface = nullptr;
364 }
365
366 env->DeleteGlobalRef(android_bluetooth_BluetoothCodecConfig.clazz);
367 android_bluetooth_BluetoothCodecConfig.clazz = nullptr;
368
369 if (mCallbacksObj != nullptr) {
370 env->DeleteGlobalRef(mCallbacksObj);
371 mCallbacksObj = nullptr;
372 }
373 }
374
connectA2dpNative(JNIEnv * env,jobject object,jbyteArray address)375 static jboolean connectA2dpNative(JNIEnv* env, jobject object,
376 jbyteArray address) {
377 ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface);
378 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
379 if (!sBluetoothA2dpInterface) {
380 ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__);
381 return JNI_FALSE;
382 }
383
384 jbyte* addr = env->GetByteArrayElements(address, nullptr);
385 if (!addr) {
386 jniThrowIOException(env, EINVAL);
387 return JNI_FALSE;
388 }
389
390 RawAddress bd_addr;
391 bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr));
392 bt_status_t status = sBluetoothA2dpInterface->connect(bd_addr);
393 if (status != BT_STATUS_SUCCESS) {
394 ALOGE("%s: Failed A2DP connection, status: %d", __func__, status);
395 }
396 env->ReleaseByteArrayElements(address, addr, 0);
397 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
398 }
399
disconnectA2dpNative(JNIEnv * env,jobject object,jbyteArray address)400 static jboolean disconnectA2dpNative(JNIEnv* env, jobject object,
401 jbyteArray address) {
402 ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface);
403 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
404 if (!sBluetoothA2dpInterface) {
405 ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__);
406 return JNI_FALSE;
407 }
408
409 jbyte* addr = env->GetByteArrayElements(address, nullptr);
410 if (!addr) {
411 jniThrowIOException(env, EINVAL);
412 return JNI_FALSE;
413 }
414
415 RawAddress bd_addr;
416 bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr));
417 bt_status_t status = sBluetoothA2dpInterface->disconnect(bd_addr);
418 if (status != BT_STATUS_SUCCESS) {
419 ALOGE("%s: Failed A2DP disconnection, status: %d", __func__, status);
420 }
421 env->ReleaseByteArrayElements(address, addr, 0);
422 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
423 }
424
setSilenceDeviceNative(JNIEnv * env,jobject object,jbyteArray address,jboolean silence)425 static jboolean setSilenceDeviceNative(JNIEnv* env, jobject object,
426 jbyteArray address, jboolean silence) {
427 ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface);
428 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
429 if (!sBluetoothA2dpInterface) {
430 ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__);
431 return JNI_FALSE;
432 }
433
434 jbyte* addr = env->GetByteArrayElements(address, nullptr);
435
436 RawAddress bd_addr = RawAddress::kEmpty;
437 if (addr) {
438 bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr));
439 }
440 if (bd_addr == RawAddress::kEmpty) {
441 return JNI_FALSE;
442 }
443 bt_status_t status =
444 sBluetoothA2dpInterface->set_silence_device(bd_addr, silence);
445 if (status != BT_STATUS_SUCCESS) {
446 ALOGE("%s: Failed A2DP set_silence_device, status: %d", __func__, status);
447 }
448 env->ReleaseByteArrayElements(address, addr, 0);
449 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
450 }
451
setActiveDeviceNative(JNIEnv * env,jobject object,jbyteArray address)452 static jboolean setActiveDeviceNative(JNIEnv* env, jobject object,
453 jbyteArray address) {
454 ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface);
455 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
456 if (!sBluetoothA2dpInterface) {
457 ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__);
458 return JNI_FALSE;
459 }
460
461 jbyte* addr = env->GetByteArrayElements(address, nullptr);
462
463 RawAddress bd_addr = RawAddress::kEmpty;
464 if (addr) {
465 bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr));
466 }
467 if (bd_addr == RawAddress::kEmpty) {
468 return JNI_FALSE;
469 }
470 bt_status_t status = sBluetoothA2dpInterface->set_active_device(bd_addr);
471 if (status != BT_STATUS_SUCCESS) {
472 ALOGE("%s: Failed A2DP set_active_device, status: %d", __func__, status);
473 }
474 env->ReleaseByteArrayElements(address, addr, 0);
475 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
476 }
477
setCodecConfigPreferenceNative(JNIEnv * env,jobject object,jbyteArray address,jobjectArray codecConfigArray)478 static jboolean setCodecConfigPreferenceNative(JNIEnv* env, jobject object,
479 jbyteArray address,
480 jobjectArray codecConfigArray) {
481 ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface);
482 std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
483 if (!sBluetoothA2dpInterface) {
484 ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__);
485 return JNI_FALSE;
486 }
487
488 jbyte* addr = env->GetByteArrayElements(address, nullptr);
489 if (!addr) {
490 jniThrowIOException(env, EINVAL);
491 return JNI_FALSE;
492 }
493
494 RawAddress bd_addr;
495 bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr));
496 std::vector<btav_a2dp_codec_config_t> codec_preferences =
497 prepareCodecPreferences(env, object, codecConfigArray);
498
499 bt_status_t status =
500 sBluetoothA2dpInterface->config_codec(bd_addr, codec_preferences);
501 if (status != BT_STATUS_SUCCESS) {
502 ALOGE("%s: Failed codec configuration, status: %d", __func__, status);
503 }
504 env->ReleaseByteArrayElements(address, addr, 0);
505 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
506 }
507
508 static JNINativeMethod sMethods[] = {
509 {"classInitNative", "()V", (void*)classInitNative},
510 {"initNative",
511 "(I[Landroid/bluetooth/BluetoothCodecConfig;[Landroid/bluetooth/BluetoothCodecConfig;)V",
512 (void*)initNative},
513 {"cleanupNative", "()V", (void*)cleanupNative},
514 {"connectA2dpNative", "([B)Z", (void*)connectA2dpNative},
515 {"disconnectA2dpNative", "([B)Z", (void*)disconnectA2dpNative},
516 {"setSilenceDeviceNative", "([BZ)Z", (void*)setSilenceDeviceNative},
517 {"setActiveDeviceNative", "([B)Z", (void*)setActiveDeviceNative},
518 {"setCodecConfigPreferenceNative",
519 "([B[Landroid/bluetooth/BluetoothCodecConfig;)Z",
520 (void*)setCodecConfigPreferenceNative},
521 };
522
register_com_android_bluetooth_a2dp(JNIEnv * env)523 int register_com_android_bluetooth_a2dp(JNIEnv* env) {
524 return jniRegisterNativeMethods(
525 env, "com/android/bluetooth/a2dp/A2dpNativeInterface", sMethods,
526 NELEM(sMethods));
527 }
528 }
529