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