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