1 /*
2 * Copyright (C) 2016 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 "BluetoothAvrcpControllerJni"
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
30 #include "com_android_bluetooth.h"
31 #include "hardware/bluetooth.h"
32 #include "hardware/bt_rc.h"
33 #include "types/raw_address.h"
34
35 namespace android {
36 static jmethodID method_onConnectionStateChanged;
37 static jmethodID method_handleplayerappsetting;
38 static jmethodID method_handleplayerappsettingchanged;
39 static jmethodID method_handleSetAbsVolume;
40 static jmethodID method_handleRegisterNotificationAbsVol;
41 static jmethodID method_handletrackchanged;
42 static jmethodID method_handleplaypositionchanged;
43 static jmethodID method_handleplaystatuschanged;
44 static jmethodID method_handleGetFolderItemsRsp;
45 static jmethodID method_handleGetPlayerItemsRsp;
46 static jmethodID method_createFromNativeMediaItem;
47 static jmethodID method_createFromNativeFolderItem;
48 static jmethodID method_createFromNativePlayerItem;
49 static jmethodID method_handleChangeFolderRsp;
50 static jmethodID method_handleSetBrowsedPlayerRsp;
51 static jmethodID method_handleSetAddressedPlayerRsp;
52 static jmethodID method_handleAddressedPlayerChanged;
53 static jmethodID method_handleNowPlayingContentChanged;
54 static jmethodID method_onAvailablePlayerChanged;
55 static jmethodID method_getRcPsm;
56
57 static jclass class_AvrcpControllerNativeInterface;
58 static jclass class_AvrcpItem;
59 static jclass class_AvrcpPlayer;
60
61 static const btrc_ctrl_interface_t* sBluetoothAvrcpInterface = NULL;
62 static jobject sCallbacksObj = NULL;
63 static std::shared_timed_mutex sCallbacks_mutex;
64
btavrcp_passthrough_response_callback(const RawAddress &,int id,int pressed)65 static void btavrcp_passthrough_response_callback(const RawAddress& /* bd_addr */, int id,
66 int pressed) {
67 log::verbose("id: {}, pressed: {} --- Not implemented", id, pressed);
68 }
69
btavrcp_groupnavigation_response_callback(int id,int pressed)70 static void btavrcp_groupnavigation_response_callback(int id, int pressed) {
71 log::verbose("id: {}, pressed: {} --- Not implemented", id, pressed);
72 }
73
btavrcp_connection_state_callback(bool rc_connect,bool br_connect,const RawAddress & bd_addr)74 static void btavrcp_connection_state_callback(bool rc_connect, bool br_connect,
75 const RawAddress& bd_addr) {
76 log::info("conn state: rc: {} br: {}", rc_connect, br_connect);
77 std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
78 CallbackEnv sCallbackEnv(__func__);
79 if (!sCallbackEnv.valid()) {
80 return;
81 }
82 if (!sCallbacksObj) {
83 log::error("sCallbacksObj is null");
84 return;
85 }
86
87 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(),
88 sCallbackEnv->NewByteArray(sizeof(RawAddress)));
89 if (!addr.get()) {
90 log::error("Failed to allocate a new byte array");
91 return;
92 }
93
94 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)bd_addr.address);
95 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_onConnectionStateChanged, (jboolean)rc_connect,
96 (jboolean)br_connect, addr.get());
97 }
98
btavrcp_get_rcfeatures_callback(const RawAddress &,int)99 static void btavrcp_get_rcfeatures_callback(const RawAddress& /* bd_addr */, int /* features */) {
100 log::verbose("--- Not implemented");
101 }
btavrcp_setplayerapplicationsetting_rsp_callback(const RawAddress &,uint8_t)102 static void btavrcp_setplayerapplicationsetting_rsp_callback(const RawAddress& /* bd_addr */,
103 uint8_t /* accepted */) {
104 log::verbose("--- Not implemented");
105 }
106
btavrcp_playerapplicationsetting_callback(const RawAddress & bd_addr,uint8_t num_attr,btrc_player_app_attr_t * app_attrs,uint8_t,btrc_player_app_ext_attr_t *)107 static void btavrcp_playerapplicationsetting_callback(const RawAddress& bd_addr, uint8_t num_attr,
108 btrc_player_app_attr_t* app_attrs,
109 uint8_t /* num_ext_attr */,
110 btrc_player_app_ext_attr_t* /* ext_attrs */) {
111 log::info("");
112 std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
113 CallbackEnv sCallbackEnv(__func__);
114 if (!sCallbackEnv.valid()) {
115 return;
116 }
117 if (!sCallbacksObj) {
118 log::error("sCallbacksObj is null");
119 return;
120 }
121
122 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(),
123 sCallbackEnv->NewByteArray(sizeof(RawAddress)));
124 if (!addr.get()) {
125 log::error("Failed to allocate a new byte array");
126 return;
127 }
128 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr.address);
129 /* TODO ext attrs
130 * Flattening defined attributes: <id,num_values,values[]>
131 */
132 jint arraylen = 0;
133 for (int i = 0; i < num_attr; i++) {
134 /*2 bytes for id and num */
135 arraylen += 2 + app_attrs[i].num_val;
136 }
137 log::verbose("arraylen {}", arraylen);
138
139 ScopedLocalRef<jbyteArray> playerattribs(sCallbackEnv.get(),
140 sCallbackEnv->NewByteArray(arraylen));
141 if (!playerattribs.get()) {
142 log::error("Failed to allocate a new byte array");
143 return;
144 }
145
146 for (int i = 0, k = 0; (i < num_attr) && (k < arraylen); i++) {
147 sCallbackEnv->SetByteArrayRegion(playerattribs.get(), k, 1, (jbyte*)&(app_attrs[i].attr_id));
148 k++;
149 sCallbackEnv->SetByteArrayRegion(playerattribs.get(), k, 1, (jbyte*)&(app_attrs[i].num_val));
150 k++;
151 sCallbackEnv->SetByteArrayRegion(playerattribs.get(), k, app_attrs[i].num_val,
152 (jbyte*)(app_attrs[i].attr_val));
153 k = k + app_attrs[i].num_val;
154 }
155 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleplayerappsetting, addr.get(),
156 playerattribs.get(), (jint)arraylen);
157 }
158
btavrcp_playerapplicationsetting_changed_callback(const RawAddress & bd_addr,const btrc_player_settings_t & vals)159 static void btavrcp_playerapplicationsetting_changed_callback(const RawAddress& bd_addr,
160 const btrc_player_settings_t& vals) {
161 log::info("");
162 std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
163 CallbackEnv sCallbackEnv(__func__);
164 if (!sCallbackEnv.valid()) {
165 return;
166 }
167 if (!sCallbacksObj) {
168 log::error("sCallbacksObj is null");
169 return;
170 }
171
172 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(),
173 sCallbackEnv->NewByteArray(sizeof(RawAddress)));
174 if (!addr.get()) {
175 log::error("Failed to allocate a new byte array");
176 return;
177 }
178 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr.address);
179
180 int arraylen = vals.num_attr * 2;
181 ScopedLocalRef<jbyteArray> playerattribs(sCallbackEnv.get(),
182 sCallbackEnv->NewByteArray(arraylen));
183 if (!playerattribs.get()) {
184 log::error("Fail to new jbyteArray playerattribs");
185 return;
186 }
187 /*
188 * Flatening format: <id,val>
189 */
190 for (int i = 0, k = 0; (i < vals.num_attr) && (k < arraylen); i++) {
191 sCallbackEnv->SetByteArrayRegion(playerattribs.get(), k, 1, (jbyte*)&(vals.attr_ids[i]));
192 k++;
193 sCallbackEnv->SetByteArrayRegion(playerattribs.get(), k, 1, (jbyte*)&(vals.attr_values[i]));
194 k++;
195 }
196 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleplayerappsettingchanged, addr.get(),
197 playerattribs.get(), (jint)arraylen);
198 }
199
btavrcp_set_abs_vol_cmd_callback(const RawAddress & bd_addr,uint8_t abs_vol,uint8_t label)200 static void btavrcp_set_abs_vol_cmd_callback(const RawAddress& bd_addr, uint8_t abs_vol,
201 uint8_t label) {
202 log::info("");
203 std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
204 CallbackEnv sCallbackEnv(__func__);
205 if (!sCallbackEnv.valid()) {
206 return;
207 }
208 if (!sCallbacksObj) {
209 log::error("sCallbacksObj is null");
210 return;
211 }
212
213 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(),
214 sCallbackEnv->NewByteArray(sizeof(RawAddress)));
215 if (!addr.get()) {
216 log::error("Failed to allocate a new byte array");
217 return;
218 }
219
220 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr.address);
221 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleSetAbsVolume, addr.get(), (jbyte)abs_vol,
222 (jbyte)label);
223 }
224
btavrcp_register_notification_absvol_callback(const RawAddress & bd_addr,uint8_t label)225 static void btavrcp_register_notification_absvol_callback(const RawAddress& bd_addr,
226 uint8_t label) {
227 log::info("");
228 std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
229 CallbackEnv sCallbackEnv(__func__);
230 if (!sCallbackEnv.valid()) {
231 return;
232 }
233 if (!sCallbacksObj) {
234 log::error("sCallbacksObj is null");
235 return;
236 }
237
238 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(),
239 sCallbackEnv->NewByteArray(sizeof(RawAddress)));
240 if (!addr.get()) {
241 log::error("Failed to allocate a new byte array");
242 return;
243 }
244
245 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr.address);
246 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleRegisterNotificationAbsVol, addr.get(),
247 (jbyte)label);
248 }
249
btavrcp_track_changed_callback(const RawAddress & bd_addr,uint8_t num_attr,btrc_element_attr_val_t * p_attrs)250 static void btavrcp_track_changed_callback(const RawAddress& bd_addr, uint8_t num_attr,
251 btrc_element_attr_val_t* p_attrs) {
252 /*
253 * byteArray will be formatted like this: id,len,string
254 * Assuming text feild to be null terminated.
255 */
256 log::info("");
257 std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
258 CallbackEnv sCallbackEnv(__func__);
259 if (!sCallbackEnv.valid()) {
260 return;
261 }
262 if (!sCallbacksObj) {
263 log::error("sCallbacksObj is null");
264 return;
265 }
266
267 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(),
268 sCallbackEnv->NewByteArray(sizeof(RawAddress)));
269 if (!addr.get()) {
270 log::error("Failed to allocate a new byte array");
271 return;
272 }
273
274 ScopedLocalRef<jintArray> attribIds(sCallbackEnv.get(), sCallbackEnv->NewIntArray(num_attr));
275 if (!attribIds.get()) {
276 log::error("failed to set new array for attribIds");
277 return;
278 }
279 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr.address);
280
281 jclass strclazz = sCallbackEnv->FindClass("java/lang/String");
282 ScopedLocalRef<jobjectArray> stringArray(
283 sCallbackEnv.get(), sCallbackEnv->NewObjectArray((jint)num_attr, strclazz, 0));
284 if (!stringArray.get()) {
285 log::error("failed to get String array");
286 return;
287 }
288
289 for (jint i = 0; i < num_attr; i++) {
290 ScopedLocalRef<jstring> str(sCallbackEnv.get(),
291 sCallbackEnv->NewStringUTF((char*)(p_attrs[i].text)));
292 if (!str.get()) {
293 log::error("Unable to get str");
294 return;
295 }
296 sCallbackEnv->SetIntArrayRegion(attribIds.get(), i, 1, (jint*)&(p_attrs[i].attr_id));
297 sCallbackEnv->SetObjectArrayElement(stringArray.get(), i, str.get());
298 }
299
300 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handletrackchanged, addr.get(),
301 (jbyte)(num_attr), attribIds.get(), stringArray.get());
302 }
303
btavrcp_play_position_changed_callback(const RawAddress & bd_addr,uint32_t song_len,uint32_t song_pos)304 static void btavrcp_play_position_changed_callback(const RawAddress& bd_addr, uint32_t song_len,
305 uint32_t song_pos) {
306 log::info("");
307 std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
308 CallbackEnv sCallbackEnv(__func__);
309 if (!sCallbackEnv.valid()) {
310 return;
311 }
312 if (!sCallbacksObj) {
313 log::error("sCallbacksObj is null");
314 return;
315 }
316
317 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(),
318 sCallbackEnv->NewByteArray(sizeof(RawAddress)));
319 if (!addr.get()) {
320 log::error("Failed to allocate a new byte array");
321 return;
322 }
323 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr.address);
324 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleplaypositionchanged, addr.get(),
325 (jint)(song_len), (jint)song_pos);
326 }
327
btavrcp_play_status_changed_callback(const RawAddress & bd_addr,btrc_play_status_t play_status)328 static void btavrcp_play_status_changed_callback(const RawAddress& bd_addr,
329 btrc_play_status_t play_status) {
330 log::info("");
331 std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
332 CallbackEnv sCallbackEnv(__func__);
333 if (!sCallbackEnv.valid()) {
334 return;
335 }
336 if (!sCallbacksObj) {
337 log::error("sCallbacksObj is null");
338 return;
339 }
340
341 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(),
342 sCallbackEnv->NewByteArray(sizeof(RawAddress)));
343 if (!addr.get()) {
344 log::error("Failed to allocate a new byte array");
345 return;
346 }
347 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr.address);
348 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleplaystatuschanged, addr.get(),
349 (jbyte)play_status);
350 }
351
btavrcp_get_folder_items_callback(const RawAddress & bd_addr,btrc_status_t status,const btrc_folder_items_t * folder_items,uint8_t count)352 static void btavrcp_get_folder_items_callback(const RawAddress& bd_addr, btrc_status_t status,
353 const btrc_folder_items_t* folder_items,
354 uint8_t count) {
355 /* Folder items are list of items that can be either BTRC_ITEM_PLAYER
356 * BTRC_ITEM_MEDIA, BTRC_ITEM_FOLDER. Here we translate them to their java
357 * counterparts by calling the java constructor for each of the items.
358 */
359 log::verbose("count {}", count);
360 std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
361 CallbackEnv sCallbackEnv(__func__);
362 if (!sCallbackEnv.valid()) {
363 return;
364 }
365 if (!sCallbacksObj) {
366 log::error("sCallbacksObj is null");
367 return;
368 }
369
370 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(),
371 sCallbackEnv->NewByteArray(sizeof(RawAddress)));
372 if (!addr.get()) {
373 log::error("Failed to allocate a new byte array");
374 return;
375 }
376
377 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr.address);
378
379 // Inspect if the first element is a folder/item or player listing. They are
380 // always exclusive.
381 bool isPlayerListing = count > 0 && (folder_items[0].item_type == BTRC_ITEM_PLAYER);
382
383 // Initialize arrays for Folder OR Player listing.
384 ScopedLocalRef<jobjectArray> itemArray(sCallbackEnv.get(), NULL);
385 if (isPlayerListing) {
386 itemArray.reset(sCallbackEnv->NewObjectArray((jint)count, class_AvrcpPlayer, 0));
387 } else {
388 itemArray.reset(sCallbackEnv->NewObjectArray((jint)count, class_AvrcpItem, 0));
389 }
390 if (!itemArray.get()) {
391 log::error("itemArray allocation failed.");
392 return;
393 }
394 for (int i = 0; i < count; i++) {
395 const btrc_folder_items_t* item = &(folder_items[i]);
396 log::verbose("item type {}", item->item_type);
397 switch (item->item_type) {
398 case BTRC_ITEM_MEDIA: {
399 // Parse name
400 ScopedLocalRef<jstring> mediaName(
401 sCallbackEnv.get(), sCallbackEnv->NewStringUTF((const char*)item->media.name));
402 if (!mediaName.get()) {
403 log::error("can't allocate media name string!");
404 return;
405 }
406 // Parse UID
407 long long uid = *(long long*)item->media.uid;
408 // Parse Attrs
409 ScopedLocalRef<jintArray> attrIdArray(sCallbackEnv.get(),
410 sCallbackEnv->NewIntArray(item->media.num_attrs));
411 if (!attrIdArray.get()) {
412 log::error("can't allocate attr id array!");
413 return;
414 }
415 ScopedLocalRef<jobjectArray> attrValArray(
416 sCallbackEnv.get(),
417 sCallbackEnv->NewObjectArray(item->media.num_attrs,
418 sCallbackEnv->FindClass("java/lang/String"), 0));
419 if (!attrValArray.get()) {
420 log::error("can't allocate attr val array!");
421 return;
422 }
423
424 for (int j = 0; j < item->media.num_attrs; j++) {
425 sCallbackEnv->SetIntArrayRegion(attrIdArray.get(), j, 1,
426 (jint*)&(item->media.p_attrs[j].attr_id));
427 ScopedLocalRef<jstring> attrValStr(
428 sCallbackEnv.get(),
429 sCallbackEnv->NewStringUTF((char*)(item->media.p_attrs[j].text)));
430 sCallbackEnv->SetObjectArrayElement(attrValArray.get(), j, attrValStr.get());
431 }
432
433 ScopedLocalRef<jobject> mediaObj(
434 sCallbackEnv.get(),
435 (jobject)sCallbackEnv->CallStaticObjectMethod(
436 class_AvrcpControllerNativeInterface, method_createFromNativeMediaItem,
437 addr.get(), uid, (jint)item->media.type, mediaName.get(), attrIdArray.get(),
438 attrValArray.get()));
439 if (!mediaObj.get()) {
440 log::error("failed to create AvrcpItem for type ITEM_MEDIA");
441 return;
442 }
443 sCallbackEnv->SetObjectArrayElement(itemArray.get(), i, mediaObj.get());
444 break;
445 }
446
447 case BTRC_ITEM_FOLDER: {
448 // Parse name
449 ScopedLocalRef<jstring> folderName(
450 sCallbackEnv.get(), sCallbackEnv->NewStringUTF((const char*)item->folder.name));
451 if (!folderName.get()) {
452 log::error("can't allocate folder name string!");
453 return;
454 }
455 // Parse UID
456 long long uid = *(long long*)item->folder.uid;
457 ScopedLocalRef<jobject> folderObj(
458 sCallbackEnv.get(),
459 (jobject)sCallbackEnv->CallStaticObjectMethod(
460 class_AvrcpControllerNativeInterface, method_createFromNativeFolderItem,
461 addr.get(), uid, (jint)item->folder.type, folderName.get(),
462 (jint)item->folder.playable));
463 if (!folderObj.get()) {
464 log::error("failed to create AvrcpItem for type ITEM_FOLDER");
465 return;
466 }
467 sCallbackEnv->SetObjectArrayElement(itemArray.get(), i, folderObj.get());
468 break;
469 }
470
471 case BTRC_ITEM_PLAYER: {
472 // Parse name
473 isPlayerListing = true;
474 jint id = (jint)item->player.player_id;
475 jint playerType = (jint)item->player.major_type;
476 jint playStatus = (jint)item->player.play_status;
477 ScopedLocalRef<jbyteArray> featureBitArray(
478 sCallbackEnv.get(),
479 sCallbackEnv->NewByteArray(BTRC_FEATURE_BIT_MASK_SIZE * sizeof(uint8_t)));
480 if (!featureBitArray.get()) {
481 log::error("failed to allocate featureBitArray");
482 return;
483 }
484 sCallbackEnv->SetByteArrayRegion(featureBitArray.get(), 0,
485 sizeof(uint8_t) * BTRC_FEATURE_BIT_MASK_SIZE,
486 (jbyte*)item->player.features);
487 ScopedLocalRef<jstring> playerName(
488 sCallbackEnv.get(), sCallbackEnv->NewStringUTF((const char*)item->player.name));
489 if (!playerName.get()) {
490 log::error("can't allocate player name string!");
491 return;
492 }
493 ScopedLocalRef<jobject> playerObj(
494 sCallbackEnv.get(),
495 (jobject)sCallbackEnv->CallStaticObjectMethod(
496 class_AvrcpControllerNativeInterface, method_createFromNativePlayerItem,
497 addr.get(), id, playerName.get(), featureBitArray.get(), playStatus,
498 playerType));
499 if (!playerObj.get()) {
500 log::error("failed to create AvrcpPlayer from ITEM_PLAYER");
501 return;
502 }
503 sCallbackEnv->SetObjectArrayElement(itemArray.get(), i, playerObj.get());
504 break;
505 }
506
507 default:
508 log::error("cannot understand type {}", item->item_type);
509 }
510 }
511
512 if (isPlayerListing) {
513 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleGetPlayerItemsRsp, addr.get(),
514 itemArray.get());
515 } else {
516 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleGetFolderItemsRsp, addr.get(), status,
517 itemArray.get());
518 }
519 }
520
btavrcp_change_path_callback(const RawAddress & bd_addr,uint32_t count)521 static void btavrcp_change_path_callback(const RawAddress& bd_addr, uint32_t count) {
522 log::info("count {}", count);
523 std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
524 CallbackEnv sCallbackEnv(__func__);
525 if (!sCallbackEnv.valid()) {
526 return;
527 }
528 if (!sCallbacksObj) {
529 log::error("sCallbacksObj is null");
530 return;
531 }
532 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(),
533 sCallbackEnv->NewByteArray(sizeof(RawAddress)));
534 if (!addr.get()) {
535 log::error("Failed to allocate a new byte array");
536 return;
537 }
538
539 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr.address);
540
541 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleChangeFolderRsp, addr.get(),
542 (jint)count);
543 }
544
btavrcp_set_browsed_player_callback(const RawAddress & bd_addr,uint8_t num_items,uint8_t depth)545 static void btavrcp_set_browsed_player_callback(const RawAddress& bd_addr, uint8_t num_items,
546 uint8_t depth) {
547 log::info("items {} depth {}", num_items, depth);
548 std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
549 CallbackEnv sCallbackEnv(__func__);
550 if (!sCallbackEnv.valid()) {
551 return;
552 }
553 if (!sCallbacksObj) {
554 log::error("sCallbacksObj is null");
555 return;
556 }
557 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(),
558 sCallbackEnv->NewByteArray(sizeof(RawAddress)));
559 if (!addr.get()) {
560 log::error("Failed to allocate a new byte array");
561 return;
562 }
563
564 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr.address);
565
566 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleSetBrowsedPlayerRsp, addr.get(),
567 (jint)num_items, (jint)depth);
568 }
569
btavrcp_set_addressed_player_callback(const RawAddress & bd_addr,uint8_t status)570 static void btavrcp_set_addressed_player_callback(const RawAddress& bd_addr, uint8_t status) {
571 log::info("status {}", status);
572 std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
573 CallbackEnv sCallbackEnv(__func__);
574 if (!sCallbackEnv.valid()) {
575 return;
576 }
577 if (!sCallbacksObj) {
578 log::error("sCallbacksObj is null");
579 return;
580 }
581 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(),
582 sCallbackEnv->NewByteArray(sizeof(RawAddress)));
583 if (!addr.get()) {
584 log::error("Failed to allocate a new byte array");
585 return;
586 }
587
588 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr.address);
589
590 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleSetAddressedPlayerRsp, addr.get(),
591 (jint)status);
592 }
593
btavrcp_addressed_player_changed_callback(const RawAddress & bd_addr,uint16_t id)594 static void btavrcp_addressed_player_changed_callback(const RawAddress& bd_addr, uint16_t id) {
595 log::info("status {}", id);
596 std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
597 CallbackEnv sCallbackEnv(__func__);
598 if (!sCallbackEnv.valid()) {
599 return;
600 }
601 if (!sCallbacksObj) {
602 log::error("sCallbacksObj is null");
603 return;
604 }
605 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(),
606 sCallbackEnv->NewByteArray(sizeof(RawAddress)));
607 if (!addr.get()) {
608 log::error("Failed to allocate a new byte array");
609 return;
610 }
611
612 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr.address);
613
614 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleAddressedPlayerChanged, addr.get(),
615 (jint)id);
616 }
617
btavrcp_now_playing_content_changed_callback(const RawAddress & bd_addr)618 static void btavrcp_now_playing_content_changed_callback(const RawAddress& bd_addr) {
619 log::info("");
620
621 CallbackEnv sCallbackEnv(__func__);
622 if (!sCallbackEnv.valid()) {
623 return;
624 }
625 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(),
626 sCallbackEnv->NewByteArray(sizeof(RawAddress)));
627 if (!addr.get()) {
628 log::error("Failed to allocate a new byte array");
629 return;
630 }
631
632 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr.address);
633
634 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleNowPlayingContentChanged, addr.get());
635 }
636
btavrcp_available_player_changed_callback(const RawAddress & bd_addr)637 static void btavrcp_available_player_changed_callback(const RawAddress& bd_addr) {
638 log::info("");
639 std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
640 CallbackEnv sCallbackEnv(__func__);
641 if (!sCallbacksObj) {
642 log::error("sCallbacksObj is null");
643 return;
644 }
645 if (!sCallbackEnv.valid()) {
646 return;
647 }
648
649 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(),
650 sCallbackEnv->NewByteArray(sizeof(RawAddress)));
651 if (!addr.get()) {
652 log::error("Failed to allocate a new byte array");
653 return;
654 }
655
656 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr);
657 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_onAvailablePlayerChanged, addr.get());
658 }
659
btavrcp_get_rcpsm_callback(const RawAddress & bd_addr,uint16_t psm)660 static void btavrcp_get_rcpsm_callback(const RawAddress& bd_addr, uint16_t psm) {
661 log::error("-> psm received of {}", psm);
662 std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
663 CallbackEnv sCallbackEnv(__func__);
664 if (!sCallbacksObj) {
665 log::error("sCallbacksObj is null");
666 return;
667 }
668 if (!sCallbackEnv.valid()) {
669 return;
670 }
671
672 ScopedLocalRef<jbyteArray> addr(sCallbackEnv.get(),
673 sCallbackEnv->NewByteArray(sizeof(RawAddress)));
674 if (!addr.get()) {
675 log::error("Failed to allocate a new byte array");
676 return;
677 }
678
679 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr.address);
680 sCallbackEnv->CallVoidMethod(sCallbacksObj, method_getRcPsm, addr.get(), (jint)psm);
681 }
682
683 static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = {
684 sizeof(sBluetoothAvrcpCallbacks),
685 btavrcp_passthrough_response_callback,
686 btavrcp_groupnavigation_response_callback,
687 btavrcp_connection_state_callback,
688 btavrcp_get_rcfeatures_callback,
689 btavrcp_setplayerapplicationsetting_rsp_callback,
690 btavrcp_playerapplicationsetting_callback,
691 btavrcp_playerapplicationsetting_changed_callback,
692 btavrcp_set_abs_vol_cmd_callback,
693 btavrcp_register_notification_absvol_callback,
694 btavrcp_track_changed_callback,
695 btavrcp_play_position_changed_callback,
696 btavrcp_play_status_changed_callback,
697 btavrcp_get_folder_items_callback,
698 btavrcp_change_path_callback,
699 btavrcp_set_browsed_player_callback,
700 btavrcp_set_addressed_player_callback,
701 btavrcp_addressed_player_changed_callback,
702 btavrcp_now_playing_content_changed_callback,
703 btavrcp_available_player_changed_callback,
704 btavrcp_get_rcpsm_callback,
705 };
706
initNative(JNIEnv * env,jobject object)707 static void initNative(JNIEnv* env, jobject object) {
708 std::unique_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
709
710 jclass tmpAvrcpItem = env->FindClass("com/android/bluetooth/avrcpcontroller/AvrcpItem");
711 class_AvrcpItem = (jclass)env->NewGlobalRef(tmpAvrcpItem);
712
713 jclass tmpBtPlayer = env->FindClass("com/android/bluetooth/avrcpcontroller/AvrcpPlayer");
714 class_AvrcpPlayer = (jclass)env->NewGlobalRef(tmpBtPlayer);
715
716 jclass tmpControllerInterface =
717 env->FindClass("com/android/bluetooth/avrcpcontroller/AvrcpControllerNativeInterface");
718 class_AvrcpControllerNativeInterface = (jclass)env->NewGlobalRef(tmpControllerInterface);
719
720 const bt_interface_t* btInf = getBluetoothInterface();
721 if (btInf == NULL) {
722 log::error("Bluetooth module is not loaded");
723 return;
724 }
725
726 if (sBluetoothAvrcpInterface != NULL) {
727 log::warn("Cleaning up Avrcp Interface before initializing...");
728 sBluetoothAvrcpInterface->cleanup();
729 sBluetoothAvrcpInterface = NULL;
730 }
731
732 if (sCallbacksObj != NULL) {
733 log::warn("Cleaning up Avrcp callback object");
734 env->DeleteGlobalRef(sCallbacksObj);
735 sCallbacksObj = NULL;
736 }
737
738 sBluetoothAvrcpInterface =
739 (btrc_ctrl_interface_t*)btInf->get_profile_interface(BT_PROFILE_AV_RC_CTRL_ID);
740 if (sBluetoothAvrcpInterface == NULL) {
741 log::error("Failed to get Bluetooth Avrcp Controller Interface");
742 return;
743 }
744
745 bt_status_t status = sBluetoothAvrcpInterface->init(&sBluetoothAvrcpCallbacks);
746 if (status != BT_STATUS_SUCCESS) {
747 log::error("Failed to initialize Bluetooth Avrcp Controller, status: {}",
748 bt_status_text(status));
749 sBluetoothAvrcpInterface = NULL;
750 return;
751 }
752
753 sCallbacksObj = env->NewGlobalRef(object);
754 }
755
cleanupNative(JNIEnv * env,jobject)756 static void cleanupNative(JNIEnv* env, jobject /* object */) {
757 std::unique_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
758
759 const bt_interface_t* btInf = getBluetoothInterface();
760 if (btInf == NULL) {
761 log::error("Bluetooth module is not loaded");
762 return;
763 }
764
765 if (sBluetoothAvrcpInterface != NULL) {
766 sBluetoothAvrcpInterface->cleanup();
767 sBluetoothAvrcpInterface = NULL;
768 }
769
770 if (sCallbacksObj != NULL) {
771 env->DeleteGlobalRef(sCallbacksObj);
772 sCallbacksObj = NULL;
773 }
774 }
775
sendPassThroughCommandNative(JNIEnv * env,jobject,jbyteArray address,jint key_code,jint key_state)776 static jboolean sendPassThroughCommandNative(JNIEnv* env, jobject /* object */, jbyteArray address,
777 jint key_code, jint key_state) {
778 if (!sBluetoothAvrcpInterface) {
779 return JNI_FALSE;
780 }
781
782 log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
783
784 log::info("key_code: {}, key_state: {}", key_code, key_state);
785
786 jbyte* addr = env->GetByteArrayElements(address, NULL);
787 if (!addr) {
788 jniThrowIOException(env, EINVAL);
789 return JNI_FALSE;
790 }
791
792 RawAddress rawAddress;
793 rawAddress.FromOctets((uint8_t*)addr);
794 bt_status_t status = sBluetoothAvrcpInterface->send_pass_through_cmd(
795 rawAddress, (uint8_t)key_code, (uint8_t)key_state);
796 if (status != BT_STATUS_SUCCESS) {
797 log::error("Failed sending passthru command, status: {}", bt_status_text(status));
798 }
799 env->ReleaseByteArrayElements(address, addr, 0);
800
801 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
802 }
803
sendGroupNavigationCommandNative(JNIEnv * env,jobject,jbyteArray address,jint key_code,jint key_state)804 static jboolean sendGroupNavigationCommandNative(JNIEnv* env, jobject /* object */,
805 jbyteArray address, jint key_code,
806 jint key_state) {
807 if (!sBluetoothAvrcpInterface) {
808 return JNI_FALSE;
809 }
810
811 log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
812
813 log::info("key_code: {}, key_state: {}", key_code, key_state);
814
815 jbyte* addr = env->GetByteArrayElements(address, NULL);
816 if (!addr) {
817 jniThrowIOException(env, EINVAL);
818 return JNI_FALSE;
819 }
820 RawAddress rawAddress;
821 rawAddress.FromOctets((uint8_t*)addr);
822
823 bt_status_t status = sBluetoothAvrcpInterface->send_group_navigation_cmd(
824 rawAddress, (uint8_t)key_code, (uint8_t)key_state);
825 if (status != BT_STATUS_SUCCESS) {
826 log::error("Failed sending Grp Navigation command, status: {}", bt_status_text(status));
827 }
828 env->ReleaseByteArrayElements(address, addr, 0);
829
830 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
831 }
832
setPlayerApplicationSettingValuesNative(JNIEnv * env,jobject,jbyteArray address,jbyte num_attrib,jbyteArray attrib_ids,jbyteArray attrib_val)833 static void setPlayerApplicationSettingValuesNative(JNIEnv* env, jobject /* object */,
834 jbyteArray address, jbyte num_attrib,
835 jbyteArray attrib_ids, jbyteArray attrib_val) {
836 log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
837 if (!sBluetoothAvrcpInterface) {
838 return;
839 }
840
841 jbyte* addr = env->GetByteArrayElements(address, NULL);
842 if (!addr) {
843 jniThrowIOException(env, EINVAL);
844 return;
845 }
846
847 uint8_t* pAttrs = new uint8_t[num_attrib];
848 uint8_t* pAttrsVal = new uint8_t[num_attrib];
849 if ((!pAttrs) || (!pAttrsVal)) {
850 delete[] pAttrs;
851 log::error("setPlayerApplicationSettingValuesNative: not have enough memory");
852 return;
853 }
854
855 jbyte* attr = env->GetByteArrayElements(attrib_ids, NULL);
856 jbyte* attr_val = env->GetByteArrayElements(attrib_val, NULL);
857 if ((!attr) || (!attr_val)) {
858 delete[] pAttrs;
859 delete[] pAttrsVal;
860 jniThrowIOException(env, EINVAL);
861 return;
862 }
863
864 for (int i = 0; i < num_attrib; ++i) {
865 pAttrs[i] = (uint8_t)attr[i];
866 pAttrsVal[i] = (uint8_t)attr_val[i];
867 }
868 RawAddress rawAddress;
869 rawAddress.FromOctets((uint8_t*)addr);
870
871 bt_status_t status = sBluetoothAvrcpInterface->set_player_app_setting_cmd(
872 rawAddress, (uint8_t)num_attrib, pAttrs, pAttrsVal);
873 if (status != BT_STATUS_SUCCESS) {
874 log::error("Failed sending setPlAppSettValNative command, status: {}", bt_status_text(status));
875 }
876 delete[] pAttrs;
877 delete[] pAttrsVal;
878 env->ReleaseByteArrayElements(attrib_ids, attr, 0);
879 env->ReleaseByteArrayElements(attrib_val, attr_val, 0);
880 env->ReleaseByteArrayElements(address, addr, 0);
881 }
882
sendAbsVolRspNative(JNIEnv * env,jobject,jbyteArray address,jint abs_vol,jint label)883 static void sendAbsVolRspNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint abs_vol,
884 jint label) {
885 if (!sBluetoothAvrcpInterface) {
886 return;
887 }
888
889 jbyte* addr = env->GetByteArrayElements(address, NULL);
890 if (!addr) {
891 jniThrowIOException(env, EINVAL);
892 return;
893 }
894
895 log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
896 RawAddress rawAddress;
897 rawAddress.FromOctets((uint8_t*)addr);
898
899 bt_status_t status =
900 sBluetoothAvrcpInterface->set_volume_rsp(rawAddress, (uint8_t)abs_vol, (uint8_t)label);
901 if (status != BT_STATUS_SUCCESS) {
902 log::error("Failed sending sendAbsVolRspNative command, status: {}", bt_status_text(status));
903 }
904 env->ReleaseByteArrayElements(address, addr, 0);
905 }
906
sendRegisterAbsVolRspNative(JNIEnv * env,jobject,jbyteArray address,jbyte rsp_type,jint abs_vol,jint label)907 static void sendRegisterAbsVolRspNative(JNIEnv* env, jobject /* object */, jbyteArray address,
908 jbyte rsp_type, jint abs_vol, jint label) {
909 if (!sBluetoothAvrcpInterface) {
910 return;
911 }
912
913 jbyte* addr = env->GetByteArrayElements(address, NULL);
914 if (!addr) {
915 jniThrowIOException(env, EINVAL);
916 return;
917 }
918 log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
919 RawAddress rawAddress;
920 rawAddress.FromOctets((uint8_t*)addr);
921
922 bt_status_t status = sBluetoothAvrcpInterface->register_abs_vol_rsp(
923 rawAddress, (btrc_notification_type_t)rsp_type, (uint8_t)abs_vol, (uint8_t)label);
924 if (status != BT_STATUS_SUCCESS) {
925 log::error("Failed sending sendRegisterAbsVolRspNative command, status: {}",
926 bt_status_text(status));
927 }
928 env->ReleaseByteArrayElements(address, addr, 0);
929 }
930
getCurrentMetadataNative(JNIEnv * env,jobject,jbyteArray address)931 static void getCurrentMetadataNative(JNIEnv* env, jobject /* object */, jbyteArray address) {
932 if (!sBluetoothAvrcpInterface) {
933 return;
934 }
935
936 jbyte* addr = env->GetByteArrayElements(address, NULL);
937 if (!addr) {
938 jniThrowIOException(env, EINVAL);
939 return;
940 }
941 log::verbose("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
942 RawAddress rawAddress;
943 rawAddress.FromOctets((uint8_t*)addr);
944
945 bt_status_t status = sBluetoothAvrcpInterface->get_current_metadata_cmd(rawAddress);
946 if (status != BT_STATUS_SUCCESS) {
947 log::error("Failed sending getCurrentMetadataNative command, status: {}",
948 bt_status_text(status));
949 }
950 env->ReleaseByteArrayElements(address, addr, 0);
951 }
952
getPlaybackStateNative(JNIEnv * env,jobject,jbyteArray address)953 static void getPlaybackStateNative(JNIEnv* env, jobject /* object */, jbyteArray address) {
954 if (!sBluetoothAvrcpInterface) {
955 return;
956 }
957
958 jbyte* addr = env->GetByteArrayElements(address, NULL);
959 if (!addr) {
960 jniThrowIOException(env, EINVAL);
961 return;
962 }
963 log::verbose("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
964 RawAddress rawAddress;
965 rawAddress.FromOctets((uint8_t*)addr);
966
967 bt_status_t status = sBluetoothAvrcpInterface->get_playback_state_cmd(rawAddress);
968 if (status != BT_STATUS_SUCCESS) {
969 log::error("Failed sending getPlaybackStateNative command, status: {}", bt_status_text(status));
970 }
971 env->ReleaseByteArrayElements(address, addr, 0);
972 }
973
getNowPlayingListNative(JNIEnv * env,jobject,jbyteArray address,jint start,jint end)974 static void getNowPlayingListNative(JNIEnv* env, jobject /* object */, jbyteArray address,
975 jint start, jint end) {
976 if (!sBluetoothAvrcpInterface) {
977 return;
978 }
979 jbyte* addr = env->GetByteArrayElements(address, NULL);
980 if (!addr) {
981 jniThrowIOException(env, EINVAL);
982 return;
983 }
984 log::verbose("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
985 RawAddress rawAddress;
986 rawAddress.FromOctets((uint8_t*)addr);
987
988 bt_status_t status = sBluetoothAvrcpInterface->get_now_playing_list_cmd(rawAddress, start, end);
989 if (status != BT_STATUS_SUCCESS) {
990 log::error("Failed sending getNowPlayingListNative command, status: {}",
991 bt_status_text(status));
992 }
993 env->ReleaseByteArrayElements(address, addr, 0);
994 }
995
getFolderListNative(JNIEnv * env,jobject,jbyteArray address,jint start,jint end)996 static void getFolderListNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint start,
997 jint end) {
998 if (!sBluetoothAvrcpInterface) {
999 return;
1000 }
1001 jbyte* addr = env->GetByteArrayElements(address, NULL);
1002 if (!addr) {
1003 jniThrowIOException(env, EINVAL);
1004 return;
1005 }
1006 log::verbose("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
1007 RawAddress rawAddress;
1008 rawAddress.FromOctets((uint8_t*)addr);
1009
1010 bt_status_t status = sBluetoothAvrcpInterface->get_folder_list_cmd(rawAddress, start, end);
1011 if (status != BT_STATUS_SUCCESS) {
1012 log::error("Failed sending getFolderListNative command, status: {}", bt_status_text(status));
1013 }
1014 env->ReleaseByteArrayElements(address, addr, 0);
1015 }
1016
getPlayerListNative(JNIEnv * env,jobject,jbyteArray address,jint start,jint end)1017 static void getPlayerListNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint start,
1018 jint end) {
1019 if (!sBluetoothAvrcpInterface) {
1020 return;
1021 }
1022 jbyte* addr = env->GetByteArrayElements(address, NULL);
1023 if (!addr) {
1024 jniThrowIOException(env, EINVAL);
1025 return;
1026 }
1027 log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
1028 RawAddress rawAddress;
1029 rawAddress.FromOctets((uint8_t*)addr);
1030
1031 bt_status_t status = sBluetoothAvrcpInterface->get_player_list_cmd(rawAddress, start, end);
1032 if (status != BT_STATUS_SUCCESS) {
1033 log::error("Failed sending getPlayerListNative command, status: {}", bt_status_text(status));
1034 }
1035 env->ReleaseByteArrayElements(address, addr, 0);
1036 }
1037
changeFolderPathNative(JNIEnv * env,jobject,jbyteArray address,jbyte direction,jlong uid)1038 static void changeFolderPathNative(JNIEnv* env, jobject /* object */, jbyteArray address,
1039 jbyte direction, jlong uid) {
1040 if (!sBluetoothAvrcpInterface) {
1041 return;
1042 }
1043 jbyte* addr = env->GetByteArrayElements(address, NULL);
1044 if (!addr) {
1045 jniThrowIOException(env, EINVAL);
1046 return;
1047 }
1048
1049 log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
1050 RawAddress rawAddress;
1051 rawAddress.FromOctets((uint8_t*)addr);
1052
1053 bt_status_t status = sBluetoothAvrcpInterface->change_folder_path_cmd(
1054 rawAddress, (uint8_t)direction, (uint8_t*)&uid);
1055 if (status != BT_STATUS_SUCCESS) {
1056 log::error("Failed sending changeFolderPathNative command, status: {}", bt_status_text(status));
1057 }
1058 env->ReleaseByteArrayElements(address, addr, 0);
1059 }
1060
setBrowsedPlayerNative(JNIEnv * env,jobject,jbyteArray address,jint id)1061 static void setBrowsedPlayerNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint id) {
1062 if (!sBluetoothAvrcpInterface) {
1063 return;
1064 }
1065 jbyte* addr = env->GetByteArrayElements(address, NULL);
1066 if (!addr) {
1067 jniThrowIOException(env, EINVAL);
1068 return;
1069 }
1070 RawAddress rawAddress;
1071 rawAddress.FromOctets((uint8_t*)addr);
1072
1073 log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
1074 bt_status_t status = sBluetoothAvrcpInterface->set_browsed_player_cmd(rawAddress, (uint16_t)id);
1075 if (status != BT_STATUS_SUCCESS) {
1076 log::error("Failed sending setBrowsedPlayerNative command, status: {}", bt_status_text(status));
1077 }
1078 env->ReleaseByteArrayElements(address, addr, 0);
1079 }
1080
setAddressedPlayerNative(JNIEnv * env,jobject,jbyteArray address,jint id)1081 static void setAddressedPlayerNative(JNIEnv* env, jobject /* object */, jbyteArray address,
1082 jint id) {
1083 if (!sBluetoothAvrcpInterface) {
1084 return;
1085 }
1086 jbyte* addr = env->GetByteArrayElements(address, NULL);
1087 if (!addr) {
1088 jniThrowIOException(env, EINVAL);
1089 return;
1090 }
1091 RawAddress rawAddress;
1092 rawAddress.FromOctets((uint8_t*)addr);
1093
1094 log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
1095 bt_status_t status = sBluetoothAvrcpInterface->set_addressed_player_cmd(rawAddress, (uint16_t)id);
1096 if (status != BT_STATUS_SUCCESS) {
1097 log::error("Failed sending setAddressedPlayerNative command, status: {}",
1098 bt_status_text(status));
1099 }
1100 env->ReleaseByteArrayElements(address, addr, 0);
1101 }
1102
playItemNative(JNIEnv * env,jobject,jbyteArray address,jbyte scope,jlong uid,jint uidCounter)1103 static void playItemNative(JNIEnv* env, jobject /* object */, jbyteArray address, jbyte scope,
1104 jlong uid, jint uidCounter) {
1105 if (!sBluetoothAvrcpInterface) {
1106 return;
1107 }
1108 jbyte* addr = env->GetByteArrayElements(address, NULL);
1109 if (!addr) {
1110 jniThrowIOException(env, EINVAL);
1111 return;
1112 }
1113
1114 RawAddress rawAddress;
1115 rawAddress.FromOctets((uint8_t*)addr);
1116
1117 log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
1118 bt_status_t status = sBluetoothAvrcpInterface->play_item_cmd(
1119 rawAddress, (uint8_t)scope, (uint8_t*)&uid, (uint16_t)uidCounter);
1120 if (status != BT_STATUS_SUCCESS) {
1121 log::error("Failed sending playItemNative command, status: {}", bt_status_text(status));
1122 }
1123 env->ReleaseByteArrayElements(address, addr, 0);
1124 }
1125
register_com_android_bluetooth_avrcp_controller(JNIEnv * env)1126 int register_com_android_bluetooth_avrcp_controller(JNIEnv* env) {
1127 const JNINativeMethod methods[] = {
1128 {"initNative", "()V", (void*)initNative},
1129 {"cleanupNative", "()V", (void*)cleanupNative},
1130 {"sendPassThroughCommandNative", "([BII)Z", (void*)sendPassThroughCommandNative},
1131 {"sendGroupNavigationCommandNative", "([BII)Z", (void*)sendGroupNavigationCommandNative},
1132 {"setPlayerApplicationSettingValuesNative", "([BB[B[B)V",
1133 (void*)setPlayerApplicationSettingValuesNative},
1134 {"sendAbsVolRspNative", "([BII)V", (void*)sendAbsVolRspNative},
1135 {"sendRegisterAbsVolRspNative", "([BBII)V", (void*)sendRegisterAbsVolRspNative},
1136 {"getCurrentMetadataNative", "([B)V", (void*)getCurrentMetadataNative},
1137 {"getPlaybackStateNative", "([B)V", (void*)getPlaybackStateNative},
1138 {"getNowPlayingListNative", "([BII)V", (void*)getNowPlayingListNative},
1139 {"getFolderListNative", "([BII)V", (void*)getFolderListNative},
1140 {"getPlayerListNative", "([BII)V", (void*)getPlayerListNative},
1141 {"changeFolderPathNative", "([BBJ)V", (void*)changeFolderPathNative},
1142 {"playItemNative", "([BBJI)V", (void*)playItemNative},
1143 {"setBrowsedPlayerNative", "([BI)V", (void*)setBrowsedPlayerNative},
1144 {"setAddressedPlayerNative", "([BI)V", (void*)setAddressedPlayerNative},
1145 };
1146 const int result = REGISTER_NATIVE_METHODS(
1147 env, "com/android/bluetooth/avrcpcontroller/AvrcpControllerNativeInterface", methods);
1148 if (result != 0) {
1149 return result;
1150 }
1151
1152 const JNIJavaMethod javaMethods[] = {
1153 {"onConnectionStateChanged", "(ZZ[B)V", &method_onConnectionStateChanged},
1154 {"getRcPsm", "([BI)V", &method_getRcPsm},
1155 {"handlePlayerAppSetting", "([B[BI)V", &method_handleplayerappsetting},
1156 {"onPlayerAppSettingChanged", "([B[BI)V", &method_handleplayerappsettingchanged},
1157 {"handleSetAbsVolume", "([BBB)V", &method_handleSetAbsVolume},
1158 {"handleRegisterNotificationAbsVol", "([BB)V", &method_handleRegisterNotificationAbsVol},
1159 {"onTrackChanged", "([BB[I[Ljava/lang/String;)V", &method_handletrackchanged},
1160 {"onPlayPositionChanged", "([BII)V", &method_handleplaypositionchanged},
1161 {"onPlayStatusChanged", "([BB)V", &method_handleplaystatuschanged},
1162 {"handleGetFolderItemsRsp", "([BI[Lcom/android/bluetooth/avrcpcontroller/AvrcpItem;)V",
1163 &method_handleGetFolderItemsRsp},
1164 {"handleGetPlayerItemsRsp", "([B[Lcom/android/bluetooth/avrcpcontroller/AvrcpPlayer;)V",
1165 &method_handleGetPlayerItemsRsp},
1166 {"handleChangeFolderRsp", "([BI)V", &method_handleChangeFolderRsp},
1167 {"handleSetBrowsedPlayerRsp", "([BII)V", &method_handleSetBrowsedPlayerRsp},
1168 {"handleSetAddressedPlayerRsp", "([BI)V", &method_handleSetAddressedPlayerRsp},
1169 {"handleAddressedPlayerChanged", "([BI)V", &method_handleAddressedPlayerChanged},
1170 {"handleNowPlayingContentChanged", "([B)V", &method_handleNowPlayingContentChanged},
1171 {"onAvailablePlayerChanged", "([B)V", &method_onAvailablePlayerChanged},
1172 // Fetch static method
1173 {"createFromNativeMediaItem",
1174 "([BJILjava/lang/String;[I[Ljava/lang/String;)"
1175 "Lcom/android/bluetooth/avrcpcontroller/AvrcpItem;",
1176 &method_createFromNativeMediaItem, true},
1177 {"createFromNativeFolderItem",
1178 "([BJILjava/lang/String;I)"
1179 "Lcom/android/bluetooth/avrcpcontroller/AvrcpItem;",
1180 &method_createFromNativeFolderItem, true},
1181 {"createFromNativePlayerItem",
1182 "([BILjava/lang/String;[BII)"
1183 "Lcom/android/bluetooth/avrcpcontroller/AvrcpPlayer;",
1184 &method_createFromNativePlayerItem, true},
1185 };
1186 GET_JAVA_METHODS(env, "com/android/bluetooth/avrcpcontroller/AvrcpControllerNativeInterface",
1187 javaMethods);
1188 return 0;
1189 }
1190 } // namespace android
1191