• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "android_runtime/AndroidRuntime.h"
22 #include "com_android_bluetooth.h"
23 #include "hardware/bt_av.h"
24 #include "utils/Log.h"
25 
26 #include <string.h>
27 #include <shared_mutex>
28 
29 namespace android {
30 static jmethodID method_onConnectionStateChanged;
31 static jmethodID method_onAudioStateChanged;
32 static jmethodID method_onCodecConfigChanged;
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 
166 static btav_source_callbacks_t sBluetoothA2dpCallbacks = {
167     sizeof(sBluetoothA2dpCallbacks), bta2dp_connection_state_callback,
168     bta2dp_audio_state_callback, bta2dp_audio_config_callback,
169 };
170 
classInitNative(JNIEnv * env,jclass clazz)171 static void classInitNative(JNIEnv* env, jclass clazz) {
172   jclass jniBluetoothCodecConfigClass =
173       env->FindClass("android/bluetooth/BluetoothCodecConfig");
174   android_bluetooth_BluetoothCodecConfig.constructor =
175       env->GetMethodID(jniBluetoothCodecConfigClass, "<init>", "(IIIIIJJJJ)V");
176   android_bluetooth_BluetoothCodecConfig.getCodecType =
177       env->GetMethodID(jniBluetoothCodecConfigClass, "getCodecType", "()I");
178   android_bluetooth_BluetoothCodecConfig.getCodecPriority =
179       env->GetMethodID(jniBluetoothCodecConfigClass, "getCodecPriority", "()I");
180   android_bluetooth_BluetoothCodecConfig.getSampleRate =
181       env->GetMethodID(jniBluetoothCodecConfigClass, "getSampleRate", "()I");
182   android_bluetooth_BluetoothCodecConfig.getBitsPerSample =
183       env->GetMethodID(jniBluetoothCodecConfigClass, "getBitsPerSample", "()I");
184   android_bluetooth_BluetoothCodecConfig.getChannelMode =
185       env->GetMethodID(jniBluetoothCodecConfigClass, "getChannelMode", "()I");
186   android_bluetooth_BluetoothCodecConfig.getCodecSpecific1 = env->GetMethodID(
187       jniBluetoothCodecConfigClass, "getCodecSpecific1", "()J");
188   android_bluetooth_BluetoothCodecConfig.getCodecSpecific2 = env->GetMethodID(
189       jniBluetoothCodecConfigClass, "getCodecSpecific2", "()J");
190   android_bluetooth_BluetoothCodecConfig.getCodecSpecific3 = env->GetMethodID(
191       jniBluetoothCodecConfigClass, "getCodecSpecific3", "()J");
192   android_bluetooth_BluetoothCodecConfig.getCodecSpecific4 = env->GetMethodID(
193       jniBluetoothCodecConfigClass, "getCodecSpecific4", "()J");
194 
195   method_onConnectionStateChanged =
196       env->GetMethodID(clazz, "onConnectionStateChanged", "([BI)V");
197 
198   method_onAudioStateChanged =
199       env->GetMethodID(clazz, "onAudioStateChanged", "([BI)V");
200 
201   method_onCodecConfigChanged =
202       env->GetMethodID(clazz, "onCodecConfigChanged",
203                        "([BLandroid/bluetooth/BluetoothCodecConfig;"
204                        "[Landroid/bluetooth/BluetoothCodecConfig;"
205                        "[Landroid/bluetooth/BluetoothCodecConfig;)V");
206 
207   ALOGI("%s: succeeds", __func__);
208 }
209 
prepareCodecPreferences(JNIEnv * env,jobject object,jobjectArray codecConfigArray)210 static std::vector<btav_a2dp_codec_config_t> prepareCodecPreferences(
211     JNIEnv* env, jobject object, jobjectArray codecConfigArray) {
212   std::vector<btav_a2dp_codec_config_t> codec_preferences;
213 
214   int numConfigs = env->GetArrayLength(codecConfigArray);
215   for (int i = 0; i < numConfigs; i++) {
216     jobject jcodecConfig = env->GetObjectArrayElement(codecConfigArray, i);
217     if (jcodecConfig == nullptr) continue;
218     if (!env->IsInstanceOf(jcodecConfig,
219                            android_bluetooth_BluetoothCodecConfig.clazz)) {
220       ALOGE("%s: Invalid BluetoothCodecConfig instance", __func__);
221       continue;
222     }
223     jint codecType = env->CallIntMethod(
224         jcodecConfig, android_bluetooth_BluetoothCodecConfig.getCodecType);
225     jint codecPriority = env->CallIntMethod(
226         jcodecConfig, android_bluetooth_BluetoothCodecConfig.getCodecPriority);
227     jint sampleRate = env->CallIntMethod(
228         jcodecConfig, android_bluetooth_BluetoothCodecConfig.getSampleRate);
229     jint bitsPerSample = env->CallIntMethod(
230         jcodecConfig, android_bluetooth_BluetoothCodecConfig.getBitsPerSample);
231     jint channelMode = env->CallIntMethod(
232         jcodecConfig, android_bluetooth_BluetoothCodecConfig.getChannelMode);
233     jlong codecSpecific1 = env->CallLongMethod(
234         jcodecConfig, android_bluetooth_BluetoothCodecConfig.getCodecSpecific1);
235     jlong codecSpecific2 = env->CallLongMethod(
236         jcodecConfig, android_bluetooth_BluetoothCodecConfig.getCodecSpecific2);
237     jlong codecSpecific3 = env->CallLongMethod(
238         jcodecConfig, android_bluetooth_BluetoothCodecConfig.getCodecSpecific3);
239     jlong codecSpecific4 = env->CallLongMethod(
240         jcodecConfig, android_bluetooth_BluetoothCodecConfig.getCodecSpecific4);
241 
242     btav_a2dp_codec_config_t codec_config = {
243         .codec_type = static_cast<btav_a2dp_codec_index_t>(codecType),
244         .codec_priority =
245             static_cast<btav_a2dp_codec_priority_t>(codecPriority),
246         .sample_rate = static_cast<btav_a2dp_codec_sample_rate_t>(sampleRate),
247         .bits_per_sample =
248             static_cast<btav_a2dp_codec_bits_per_sample_t>(bitsPerSample),
249         .channel_mode =
250             static_cast<btav_a2dp_codec_channel_mode_t>(channelMode),
251         .codec_specific_1 = codecSpecific1,
252         .codec_specific_2 = codecSpecific2,
253         .codec_specific_3 = codecSpecific3,
254         .codec_specific_4 = codecSpecific4};
255 
256     codec_preferences.push_back(codec_config);
257   }
258   return codec_preferences;
259 }
260 
initNative(JNIEnv * env,jobject object,jint maxConnectedAudioDevices,jobjectArray codecConfigArray)261 static void initNative(JNIEnv* env, jobject object,
262                        jint maxConnectedAudioDevices,
263                        jobjectArray codecConfigArray) {
264   std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
265   std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
266 
267   const bt_interface_t* btInf = getBluetoothInterface();
268   if (btInf == nullptr) {
269     ALOGE("%s: Bluetooth module is not loaded", __func__);
270     return;
271   }
272 
273   if (sBluetoothA2dpInterface != nullptr) {
274     ALOGW("%s: Cleaning up A2DP Interface before initializing...", __func__);
275     sBluetoothA2dpInterface->cleanup();
276     sBluetoothA2dpInterface = nullptr;
277   }
278 
279   if (mCallbacksObj != nullptr) {
280     ALOGW("%s: Cleaning up A2DP callback object", __func__);
281     env->DeleteGlobalRef(mCallbacksObj);
282     mCallbacksObj = nullptr;
283   }
284 
285   if ((mCallbacksObj = env->NewGlobalRef(object)) == nullptr) {
286     ALOGE("%s: Failed to allocate Global Ref for A2DP Callbacks", __func__);
287     return;
288   }
289 
290   android_bluetooth_BluetoothCodecConfig.clazz = (jclass)env->NewGlobalRef(
291       env->FindClass("android/bluetooth/BluetoothCodecConfig"));
292   if (android_bluetooth_BluetoothCodecConfig.clazz == nullptr) {
293     ALOGE("%s: Failed to allocate Global Ref for BluetoothCodecConfig class",
294           __func__);
295     return;
296   }
297 
298   sBluetoothA2dpInterface =
299       (btav_source_interface_t*)btInf->get_profile_interface(
300           BT_PROFILE_ADVANCED_AUDIO_ID);
301   if (sBluetoothA2dpInterface == nullptr) {
302     ALOGE("%s: Failed to get Bluetooth A2DP Interface", __func__);
303     return;
304   }
305 
306   std::vector<btav_a2dp_codec_config_t> codec_priorities =
307       prepareCodecPreferences(env, object, codecConfigArray);
308 
309   bt_status_t status = sBluetoothA2dpInterface->init(
310       &sBluetoothA2dpCallbacks, maxConnectedAudioDevices, codec_priorities);
311   if (status != BT_STATUS_SUCCESS) {
312     ALOGE("%s: Failed to initialize Bluetooth A2DP, status: %d", __func__,
313           status);
314     sBluetoothA2dpInterface = nullptr;
315     return;
316   }
317 }
318 
cleanupNative(JNIEnv * env,jobject object)319 static void cleanupNative(JNIEnv* env, jobject object) {
320   std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
321   std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
322 
323   const bt_interface_t* btInf = getBluetoothInterface();
324   if (btInf == nullptr) {
325     ALOGE("%s: Bluetooth module is not loaded", __func__);
326     return;
327   }
328 
329   if (sBluetoothA2dpInterface != nullptr) {
330     sBluetoothA2dpInterface->cleanup();
331     sBluetoothA2dpInterface = nullptr;
332   }
333 
334   env->DeleteGlobalRef(android_bluetooth_BluetoothCodecConfig.clazz);
335   android_bluetooth_BluetoothCodecConfig.clazz = nullptr;
336 
337   if (mCallbacksObj != nullptr) {
338     env->DeleteGlobalRef(mCallbacksObj);
339     mCallbacksObj = nullptr;
340   }
341 }
342 
connectA2dpNative(JNIEnv * env,jobject object,jbyteArray address)343 static jboolean connectA2dpNative(JNIEnv* env, jobject object,
344                                   jbyteArray address) {
345   ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface);
346   std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
347   if (!sBluetoothA2dpInterface) {
348     ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__);
349     return JNI_FALSE;
350   }
351 
352   jbyte* addr = env->GetByteArrayElements(address, nullptr);
353   if (!addr) {
354     jniThrowIOException(env, EINVAL);
355     return JNI_FALSE;
356   }
357 
358   RawAddress bd_addr;
359   bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr));
360   bt_status_t status = sBluetoothA2dpInterface->connect(bd_addr);
361   if (status != BT_STATUS_SUCCESS) {
362     ALOGE("%s: Failed A2DP connection, status: %d", __func__, status);
363   }
364   env->ReleaseByteArrayElements(address, addr, 0);
365   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
366 }
367 
disconnectA2dpNative(JNIEnv * env,jobject object,jbyteArray address)368 static jboolean disconnectA2dpNative(JNIEnv* env, jobject object,
369                                      jbyteArray address) {
370   ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface);
371   std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
372   if (!sBluetoothA2dpInterface) {
373     ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__);
374     return JNI_FALSE;
375   }
376 
377   jbyte* addr = env->GetByteArrayElements(address, nullptr);
378   if (!addr) {
379     jniThrowIOException(env, EINVAL);
380     return JNI_FALSE;
381   }
382 
383   RawAddress bd_addr;
384   bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr));
385   bt_status_t status = sBluetoothA2dpInterface->disconnect(bd_addr);
386   if (status != BT_STATUS_SUCCESS) {
387     ALOGE("%s: Failed A2DP disconnection, status: %d", __func__, status);
388   }
389   env->ReleaseByteArrayElements(address, addr, 0);
390   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
391 }
392 
setSilenceDeviceNative(JNIEnv * env,jobject object,jbyteArray address,jboolean silence)393 static jboolean setSilenceDeviceNative(JNIEnv* env, jobject object,
394                                        jbyteArray address, jboolean silence) {
395   ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface);
396   std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
397   if (!sBluetoothA2dpInterface) {
398     ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__);
399     return JNI_FALSE;
400   }
401 
402   jbyte* addr = env->GetByteArrayElements(address, nullptr);
403 
404   RawAddress bd_addr = RawAddress::kEmpty;
405   if (addr) {
406     bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr));
407   }
408   if (bd_addr == RawAddress::kEmpty) {
409     return JNI_FALSE;
410   }
411   bt_status_t status =
412       sBluetoothA2dpInterface->set_silence_device(bd_addr, silence);
413   if (status != BT_STATUS_SUCCESS) {
414     ALOGE("%s: Failed A2DP set_silence_device, status: %d", __func__, status);
415   }
416   env->ReleaseByteArrayElements(address, addr, 0);
417   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
418 }
419 
setActiveDeviceNative(JNIEnv * env,jobject object,jbyteArray address)420 static jboolean setActiveDeviceNative(JNIEnv* env, jobject object,
421                                       jbyteArray address) {
422   ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface);
423   std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
424   if (!sBluetoothA2dpInterface) {
425     ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__);
426     return JNI_FALSE;
427   }
428 
429   jbyte* addr = env->GetByteArrayElements(address, nullptr);
430 
431   RawAddress bd_addr = RawAddress::kEmpty;
432   if (addr) {
433     bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr));
434   }
435   if (bd_addr == RawAddress::kEmpty) {
436     return JNI_FALSE;
437   }
438   bt_status_t status = sBluetoothA2dpInterface->set_active_device(bd_addr);
439   if (status != BT_STATUS_SUCCESS) {
440     ALOGE("%s: Failed A2DP set_active_device, status: %d", __func__, status);
441   }
442   env->ReleaseByteArrayElements(address, addr, 0);
443   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
444 }
445 
setCodecConfigPreferenceNative(JNIEnv * env,jobject object,jbyteArray address,jobjectArray codecConfigArray)446 static jboolean setCodecConfigPreferenceNative(JNIEnv* env, jobject object,
447                                                jbyteArray address,
448                                                jobjectArray codecConfigArray) {
449   ALOGI("%s: sBluetoothA2dpInterface: %p", __func__, sBluetoothA2dpInterface);
450   std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
451   if (!sBluetoothA2dpInterface) {
452     ALOGE("%s: Failed to get the Bluetooth A2DP Interface", __func__);
453     return JNI_FALSE;
454   }
455 
456   jbyte* addr = env->GetByteArrayElements(address, nullptr);
457   if (!addr) {
458     jniThrowIOException(env, EINVAL);
459     return JNI_FALSE;
460   }
461 
462   RawAddress bd_addr;
463   bd_addr.FromOctets(reinterpret_cast<const uint8_t*>(addr));
464   std::vector<btav_a2dp_codec_config_t> codec_preferences =
465       prepareCodecPreferences(env, object, codecConfigArray);
466 
467   bt_status_t status =
468       sBluetoothA2dpInterface->config_codec(bd_addr, codec_preferences);
469   if (status != BT_STATUS_SUCCESS) {
470     ALOGE("%s: Failed codec configuration, status: %d", __func__, status);
471   }
472   env->ReleaseByteArrayElements(address, addr, 0);
473   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
474 }
475 
476 static JNINativeMethod sMethods[] = {
477     {"classInitNative", "()V", (void*)classInitNative},
478     {"initNative", "(I[Landroid/bluetooth/BluetoothCodecConfig;)V",
479      (void*)initNative},
480     {"cleanupNative", "()V", (void*)cleanupNative},
481     {"connectA2dpNative", "([B)Z", (void*)connectA2dpNative},
482     {"disconnectA2dpNative", "([B)Z", (void*)disconnectA2dpNative},
483     {"setSilenceDeviceNative", "([BZ)Z", (void*)setSilenceDeviceNative},
484     {"setActiveDeviceNative", "([B)Z", (void*)setActiveDeviceNative},
485     {"setCodecConfigPreferenceNative",
486      "([B[Landroid/bluetooth/BluetoothCodecConfig;)Z",
487      (void*)setCodecConfigPreferenceNative},
488 };
489 
register_com_android_bluetooth_a2dp(JNIEnv * env)490 int register_com_android_bluetooth_a2dp(JNIEnv* env) {
491   return jniRegisterNativeMethods(
492       env, "com/android/bluetooth/a2dp/A2dpNativeInterface", sMethods,
493       NELEM(sMethods));
494 }
495 }
496