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