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