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