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