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 int i;
865 for (i = 0; i < num_attrib; ++i) {
866 pAttrs[i] = (uint8_t)attr[i];
867 pAttrsVal[i] = (uint8_t)attr_val[i];
868 }
869 RawAddress rawAddress;
870 rawAddress.FromOctets((uint8_t*)addr);
871
872 bt_status_t status = sBluetoothAvrcpInterface->set_player_app_setting_cmd(
873 rawAddress, (uint8_t)num_attrib, pAttrs, pAttrsVal);
874 if (status != BT_STATUS_SUCCESS) {
875 log::error("Failed sending setPlAppSettValNative command, status: {}", bt_status_text(status));
876 }
877 delete[] pAttrs;
878 delete[] pAttrsVal;
879 env->ReleaseByteArrayElements(attrib_ids, attr, 0);
880 env->ReleaseByteArrayElements(attrib_val, attr_val, 0);
881 env->ReleaseByteArrayElements(address, addr, 0);
882 }
883
sendAbsVolRspNative(JNIEnv * env,jobject,jbyteArray address,jint abs_vol,jint label)884 static void sendAbsVolRspNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint abs_vol,
885 jint label) {
886 if (!sBluetoothAvrcpInterface) {
887 return;
888 }
889
890 jbyte* addr = env->GetByteArrayElements(address, NULL);
891 if (!addr) {
892 jniThrowIOException(env, EINVAL);
893 return;
894 }
895
896 log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
897 RawAddress rawAddress;
898 rawAddress.FromOctets((uint8_t*)addr);
899
900 bt_status_t status =
901 sBluetoothAvrcpInterface->set_volume_rsp(rawAddress, (uint8_t)abs_vol, (uint8_t)label);
902 if (status != BT_STATUS_SUCCESS) {
903 log::error("Failed sending sendAbsVolRspNative command, status: {}", bt_status_text(status));
904 }
905 env->ReleaseByteArrayElements(address, addr, 0);
906 }
907
sendRegisterAbsVolRspNative(JNIEnv * env,jobject,jbyteArray address,jbyte rsp_type,jint abs_vol,jint label)908 static void sendRegisterAbsVolRspNative(JNIEnv* env, jobject /* object */, jbyteArray address,
909 jbyte rsp_type, jint abs_vol, jint label) {
910 if (!sBluetoothAvrcpInterface) {
911 return;
912 }
913
914 jbyte* addr = env->GetByteArrayElements(address, NULL);
915 if (!addr) {
916 jniThrowIOException(env, EINVAL);
917 return;
918 }
919 log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
920 RawAddress rawAddress;
921 rawAddress.FromOctets((uint8_t*)addr);
922
923 bt_status_t status = sBluetoothAvrcpInterface->register_abs_vol_rsp(
924 rawAddress, (btrc_notification_type_t)rsp_type, (uint8_t)abs_vol, (uint8_t)label);
925 if (status != BT_STATUS_SUCCESS) {
926 log::error("Failed sending sendRegisterAbsVolRspNative command, status: {}",
927 bt_status_text(status));
928 }
929 env->ReleaseByteArrayElements(address, addr, 0);
930 }
931
getCurrentMetadataNative(JNIEnv * env,jobject,jbyteArray address)932 static void getCurrentMetadataNative(JNIEnv* env, jobject /* object */, jbyteArray address) {
933 if (!sBluetoothAvrcpInterface) {
934 return;
935 }
936
937 jbyte* addr = env->GetByteArrayElements(address, NULL);
938 if (!addr) {
939 jniThrowIOException(env, EINVAL);
940 return;
941 }
942 log::verbose("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
943 RawAddress rawAddress;
944 rawAddress.FromOctets((uint8_t*)addr);
945
946 bt_status_t status = sBluetoothAvrcpInterface->get_current_metadata_cmd(rawAddress);
947 if (status != BT_STATUS_SUCCESS) {
948 log::error("Failed sending getCurrentMetadataNative command, status: {}",
949 bt_status_text(status));
950 }
951 env->ReleaseByteArrayElements(address, addr, 0);
952 }
953
getPlaybackStateNative(JNIEnv * env,jobject,jbyteArray address)954 static void getPlaybackStateNative(JNIEnv* env, jobject /* object */, jbyteArray address) {
955 if (!sBluetoothAvrcpInterface) {
956 return;
957 }
958
959 jbyte* addr = env->GetByteArrayElements(address, NULL);
960 if (!addr) {
961 jniThrowIOException(env, EINVAL);
962 return;
963 }
964 log::verbose("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
965 RawAddress rawAddress;
966 rawAddress.FromOctets((uint8_t*)addr);
967
968 bt_status_t status = sBluetoothAvrcpInterface->get_playback_state_cmd(rawAddress);
969 if (status != BT_STATUS_SUCCESS) {
970 log::error("Failed sending getPlaybackStateNative command, status: {}", bt_status_text(status));
971 }
972 env->ReleaseByteArrayElements(address, addr, 0);
973 }
974
getNowPlayingListNative(JNIEnv * env,jobject,jbyteArray address,jint start,jint end)975 static void getNowPlayingListNative(JNIEnv* env, jobject /* object */, jbyteArray address,
976 jint start, jint end) {
977 if (!sBluetoothAvrcpInterface) {
978 return;
979 }
980 jbyte* addr = env->GetByteArrayElements(address, NULL);
981 if (!addr) {
982 jniThrowIOException(env, EINVAL);
983 return;
984 }
985 log::verbose("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
986 RawAddress rawAddress;
987 rawAddress.FromOctets((uint8_t*)addr);
988
989 bt_status_t status = sBluetoothAvrcpInterface->get_now_playing_list_cmd(rawAddress, start, end);
990 if (status != BT_STATUS_SUCCESS) {
991 log::error("Failed sending getNowPlayingListNative command, status: {}",
992 bt_status_text(status));
993 }
994 env->ReleaseByteArrayElements(address, addr, 0);
995 }
996
getFolderListNative(JNIEnv * env,jobject,jbyteArray address,jint start,jint end)997 static void getFolderListNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint start,
998 jint end) {
999 if (!sBluetoothAvrcpInterface) {
1000 return;
1001 }
1002 jbyte* addr = env->GetByteArrayElements(address, NULL);
1003 if (!addr) {
1004 jniThrowIOException(env, EINVAL);
1005 return;
1006 }
1007 log::verbose("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
1008 RawAddress rawAddress;
1009 rawAddress.FromOctets((uint8_t*)addr);
1010
1011 bt_status_t status = sBluetoothAvrcpInterface->get_folder_list_cmd(rawAddress, start, end);
1012 if (status != BT_STATUS_SUCCESS) {
1013 log::error("Failed sending getFolderListNative command, status: {}", bt_status_text(status));
1014 }
1015 env->ReleaseByteArrayElements(address, addr, 0);
1016 }
1017
getPlayerListNative(JNIEnv * env,jobject,jbyteArray address,jint start,jint end)1018 static void getPlayerListNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint start,
1019 jint end) {
1020 if (!sBluetoothAvrcpInterface) {
1021 return;
1022 }
1023 jbyte* addr = env->GetByteArrayElements(address, NULL);
1024 if (!addr) {
1025 jniThrowIOException(env, EINVAL);
1026 return;
1027 }
1028 log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
1029 RawAddress rawAddress;
1030 rawAddress.FromOctets((uint8_t*)addr);
1031
1032 bt_status_t status = sBluetoothAvrcpInterface->get_player_list_cmd(rawAddress, start, end);
1033 if (status != BT_STATUS_SUCCESS) {
1034 log::error("Failed sending getPlayerListNative command, status: {}", bt_status_text(status));
1035 }
1036 env->ReleaseByteArrayElements(address, addr, 0);
1037 }
1038
changeFolderPathNative(JNIEnv * env,jobject,jbyteArray address,jbyte direction,jlong uid)1039 static void changeFolderPathNative(JNIEnv* env, jobject /* object */, jbyteArray address,
1040 jbyte direction, jlong uid) {
1041 if (!sBluetoothAvrcpInterface) {
1042 return;
1043 }
1044 jbyte* addr = env->GetByteArrayElements(address, NULL);
1045 if (!addr) {
1046 jniThrowIOException(env, EINVAL);
1047 return;
1048 }
1049
1050 // jbyte* uid = env->GetByteArrayElements(uidarr, NULL);
1051 // if (!uid) {
1052 // jniThrowIOException(env, EINVAL);
1053 // return;
1054 //}
1055
1056 log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
1057 RawAddress rawAddress;
1058 rawAddress.FromOctets((uint8_t*)addr);
1059
1060 bt_status_t status = sBluetoothAvrcpInterface->change_folder_path_cmd(
1061 rawAddress, (uint8_t)direction, (uint8_t*)&uid);
1062 if (status != BT_STATUS_SUCCESS) {
1063 log::error("Failed sending changeFolderPathNative command, status: {}", bt_status_text(status));
1064 }
1065 // env->ReleaseByteArrayElements(address, addr, 0);
1066 }
1067
setBrowsedPlayerNative(JNIEnv * env,jobject,jbyteArray address,jint id)1068 static void setBrowsedPlayerNative(JNIEnv* env, jobject /* object */, jbyteArray address, jint id) {
1069 if (!sBluetoothAvrcpInterface) {
1070 return;
1071 }
1072 jbyte* addr = env->GetByteArrayElements(address, NULL);
1073 if (!addr) {
1074 jniThrowIOException(env, EINVAL);
1075 return;
1076 }
1077 RawAddress rawAddress;
1078 rawAddress.FromOctets((uint8_t*)addr);
1079
1080 log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
1081 bt_status_t status = sBluetoothAvrcpInterface->set_browsed_player_cmd(rawAddress, (uint16_t)id);
1082 if (status != BT_STATUS_SUCCESS) {
1083 log::error("Failed sending setBrowsedPlayerNative command, status: {}", bt_status_text(status));
1084 }
1085 env->ReleaseByteArrayElements(address, addr, 0);
1086 }
1087
setAddressedPlayerNative(JNIEnv * env,jobject,jbyteArray address,jint id)1088 static void setAddressedPlayerNative(JNIEnv* env, jobject /* object */, jbyteArray address,
1089 jint id) {
1090 if (!sBluetoothAvrcpInterface) {
1091 return;
1092 }
1093 jbyte* addr = env->GetByteArrayElements(address, NULL);
1094 if (!addr) {
1095 jniThrowIOException(env, EINVAL);
1096 return;
1097 }
1098 RawAddress rawAddress;
1099 rawAddress.FromOctets((uint8_t*)addr);
1100
1101 log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
1102 bt_status_t status = sBluetoothAvrcpInterface->set_addressed_player_cmd(rawAddress, (uint16_t)id);
1103 if (status != BT_STATUS_SUCCESS) {
1104 log::error("Failed sending setAddressedPlayerNative command, status: {}",
1105 bt_status_text(status));
1106 }
1107 env->ReleaseByteArrayElements(address, addr, 0);
1108 }
1109
playItemNative(JNIEnv * env,jobject,jbyteArray address,jbyte scope,jlong uid,jint uidCounter)1110 static void playItemNative(JNIEnv* env, jobject /* object */, jbyteArray address, jbyte scope,
1111 jlong uid, jint uidCounter) {
1112 if (!sBluetoothAvrcpInterface) {
1113 return;
1114 }
1115 jbyte* addr = env->GetByteArrayElements(address, NULL);
1116 if (!addr) {
1117 jniThrowIOException(env, EINVAL);
1118 return;
1119 }
1120
1121 // jbyte* uid = env->GetByteArrayElements(uidArr, NULL);
1122 // if (!uid) {
1123 // jniThrowIOException(env, EINVAL);
1124 // return;
1125 // }
1126 RawAddress rawAddress;
1127 rawAddress.FromOctets((uint8_t*)addr);
1128
1129 log::info("sBluetoothAvrcpInterface: {}", std::format_ptr(sBluetoothAvrcpInterface));
1130 bt_status_t status = sBluetoothAvrcpInterface->play_item_cmd(
1131 rawAddress, (uint8_t)scope, (uint8_t*)&uid, (uint16_t)uidCounter);
1132 if (status != BT_STATUS_SUCCESS) {
1133 log::error("Failed sending playItemNative command, status: {}", bt_status_text(status));
1134 }
1135 env->ReleaseByteArrayElements(address, addr, 0);
1136 }
1137
register_com_android_bluetooth_avrcp_controller(JNIEnv * env)1138 int register_com_android_bluetooth_avrcp_controller(JNIEnv* env) {
1139 const JNINativeMethod methods[] = {
1140 {"initNative", "()V", (void*)initNative},
1141 {"cleanupNative", "()V", (void*)cleanupNative},
1142 {"sendPassThroughCommandNative", "([BII)Z", (void*)sendPassThroughCommandNative},
1143 {"sendGroupNavigationCommandNative", "([BII)Z", (void*)sendGroupNavigationCommandNative},
1144 {"setPlayerApplicationSettingValuesNative", "([BB[B[B)V",
1145 (void*)setPlayerApplicationSettingValuesNative},
1146 {"sendAbsVolRspNative", "([BII)V", (void*)sendAbsVolRspNative},
1147 {"sendRegisterAbsVolRspNative", "([BBII)V", (void*)sendRegisterAbsVolRspNative},
1148 {"getCurrentMetadataNative", "([B)V", (void*)getCurrentMetadataNative},
1149 {"getPlaybackStateNative", "([B)V", (void*)getPlaybackStateNative},
1150 {"getNowPlayingListNative", "([BII)V", (void*)getNowPlayingListNative},
1151 {"getFolderListNative", "([BII)V", (void*)getFolderListNative},
1152 {"getPlayerListNative", "([BII)V", (void*)getPlayerListNative},
1153 {"changeFolderPathNative", "([BBJ)V", (void*)changeFolderPathNative},
1154 {"playItemNative", "([BBJI)V", (void*)playItemNative},
1155 {"setBrowsedPlayerNative", "([BI)V", (void*)setBrowsedPlayerNative},
1156 {"setAddressedPlayerNative", "([BI)V", (void*)setAddressedPlayerNative},
1157 };
1158 const int result = REGISTER_NATIVE_METHODS(
1159 env, "com/android/bluetooth/avrcpcontroller/AvrcpControllerNativeInterface", methods);
1160 if (result != 0) {
1161 return result;
1162 }
1163
1164 const JNIJavaMethod javaMethods[] = {
1165 {"onConnectionStateChanged", "(ZZ[B)V", &method_onConnectionStateChanged},
1166 {"getRcPsm", "([BI)V", &method_getRcPsm},
1167 {"handlePlayerAppSetting", "([B[BI)V", &method_handleplayerappsetting},
1168 {"onPlayerAppSettingChanged", "([B[BI)V", &method_handleplayerappsettingchanged},
1169 {"handleSetAbsVolume", "([BBB)V", &method_handleSetAbsVolume},
1170 {"handleRegisterNotificationAbsVol", "([BB)V", &method_handleRegisterNotificationAbsVol},
1171 {"onTrackChanged", "([BB[I[Ljava/lang/String;)V", &method_handletrackchanged},
1172 {"onPlayPositionChanged", "([BII)V", &method_handleplaypositionchanged},
1173 {"onPlayStatusChanged", "([BB)V", &method_handleplaystatuschanged},
1174 {"handleGetFolderItemsRsp", "([BI[Lcom/android/bluetooth/avrcpcontroller/AvrcpItem;)V",
1175 &method_handleGetFolderItemsRsp},
1176 {"handleGetPlayerItemsRsp", "([B[Lcom/android/bluetooth/avrcpcontroller/AvrcpPlayer;)V",
1177 &method_handleGetPlayerItemsRsp},
1178 {"handleChangeFolderRsp", "([BI)V", &method_handleChangeFolderRsp},
1179 {"handleSetBrowsedPlayerRsp", "([BII)V", &method_handleSetBrowsedPlayerRsp},
1180 {"handleSetAddressedPlayerRsp", "([BI)V", &method_handleSetAddressedPlayerRsp},
1181 {"handleAddressedPlayerChanged", "([BI)V", &method_handleAddressedPlayerChanged},
1182 {"handleNowPlayingContentChanged", "([B)V", &method_handleNowPlayingContentChanged},
1183 {"onAvailablePlayerChanged", "([B)V", &method_onAvailablePlayerChanged},
1184 // Fetch static method
1185 {"createFromNativeMediaItem",
1186 "([BJILjava/lang/String;[I[Ljava/lang/String;)"
1187 "Lcom/android/bluetooth/avrcpcontroller/AvrcpItem;",
1188 &method_createFromNativeMediaItem, true},
1189 {"createFromNativeFolderItem",
1190 "([BJILjava/lang/String;I)"
1191 "Lcom/android/bluetooth/avrcpcontroller/AvrcpItem;",
1192 &method_createFromNativeFolderItem, true},
1193 {"createFromNativePlayerItem",
1194 "([BILjava/lang/String;[BII)"
1195 "Lcom/android/bluetooth/avrcpcontroller/AvrcpPlayer;",
1196 &method_createFromNativePlayerItem, true},
1197 };
1198 GET_JAVA_METHODS(env, "com/android/bluetooth/avrcpcontroller/AvrcpControllerNativeInterface",
1199 javaMethods);
1200 return 0;
1201 }
1202 } // namespace android
1203