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