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