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 "BluetoothAvrcpServiceJni" 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 <inttypes.h> 27 #include <string.h> 28 29 namespace android { 30 static jmethodID method_getRcFeatures; 31 static jmethodID method_getPlayStatus; 32 static jmethodID method_getElementAttr; 33 static jmethodID method_registerNotification; 34 static jmethodID method_volumeChangeCallback; 35 static jmethodID method_handlePassthroughCmd; 36 static jmethodID method_getFolderItemsCallback; 37 static jmethodID method_setAddressedPlayerCallback; 38 39 static jmethodID method_setBrowsedPlayerCallback; 40 static jmethodID method_changePathCallback; 41 static jmethodID method_searchCallback; 42 static jmethodID method_playItemCallback; 43 static jmethodID method_getItemAttrCallback; 44 static jmethodID method_addToPlayListCallback; 45 static jmethodID method_getTotalNumOfItemsCallback; 46 47 static const btrc_interface_t* sBluetoothAvrcpInterface = NULL; 48 static jobject mCallbacksObj = NULL; 49 50 /* Function declarations */ 51 static bool copy_item_attributes(JNIEnv* env, jobject object, 52 btrc_folder_items_t* pitem, 53 jint* p_attributesIds, 54 jobjectArray attributesArray, int item_idx, 55 int attribCopiedIndex); 56 57 static bool copy_jstring(uint8_t* str, int maxBytes, jstring jstr, JNIEnv* env); 58 59 static void cleanup_items(btrc_folder_items_t* p_items, int numItems); 60 61 static void btavrcp_remote_features_callback(const RawAddress& bd_addr, 62 btrc_remote_features_t features) { 63 CallbackEnv sCallbackEnv(__func__); 64 if (!sCallbackEnv.valid()) return; 65 66 if (!mCallbacksObj) { 67 ALOGE("%s: mCallbacksObj is null", __func__); 68 return; 69 } 70 71 ScopedLocalRef<jbyteArray> addr( 72 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); 73 if (!addr.get()) { 74 ALOGE("Unable to allocate byte array for bd_addr"); 75 return; 76 } 77 78 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), 79 (jbyte*)bd_addr.address); 80 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getRcFeatures, addr.get(), 81 (jint)features); 82 } 83 84 /** Callback for play status request */ 85 static void btavrcp_get_play_status_callback(const RawAddress& bd_addr) { 86 CallbackEnv sCallbackEnv(__func__); 87 if (!sCallbackEnv.valid()) return; 88 89 if (!mCallbacksObj) { 90 ALOGE("%s: mCallbacksObj is null", __func__); 91 return; 92 } 93 94 ScopedLocalRef<jbyteArray> addr( 95 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); 96 if (!addr.get()) { 97 ALOGE("Fail to new jbyteArray bd addr for get_play_status command"); 98 return; 99 } 100 101 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), 102 (jbyte*)bd_addr.address); 103 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getPlayStatus, addr.get()); 104 } 105 106 static void btavrcp_get_element_attr_callback(uint8_t num_attr, 107 btrc_media_attr_t* p_attrs, 108 const RawAddress& bd_addr) { 109 CallbackEnv sCallbackEnv(__func__); 110 if (!sCallbackEnv.valid()) return; 111 112 if (!mCallbacksObj) { 113 ALOGE("%s: mCallbacksObj is null", __func__); 114 return; 115 } 116 117 ScopedLocalRef<jbyteArray> addr( 118 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); 119 if (!addr.get()) { 120 ALOGE("Fail to new jbyteArray bd addr for get_element_attr command"); 121 return; 122 } 123 124 ScopedLocalRef<jintArray> attrs( 125 sCallbackEnv.get(), (jintArray)sCallbackEnv->NewIntArray(num_attr)); 126 if (!attrs.get()) { 127 ALOGE("Fail to new jintArray for attrs"); 128 return; 129 } 130 131 sCallbackEnv->SetIntArrayRegion(attrs.get(), 0, num_attr, (jint*)p_attrs); 132 133 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), 134 (jbyte*)bd_addr.address); 135 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getElementAttr, addr.get(), 136 (jbyte)num_attr, attrs.get()); 137 } 138 139 static void btavrcp_register_notification_callback(btrc_event_id_t event_id, 140 uint32_t param, 141 const RawAddress& bd_addr) { 142 CallbackEnv sCallbackEnv(__func__); 143 if (!sCallbackEnv.valid()) return; 144 145 if (!mCallbacksObj) { 146 ALOGE("%s: mCallbacksObj is null", __func__); 147 return; 148 } 149 150 ScopedLocalRef<jbyteArray> addr( 151 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); 152 if (!addr.get()) { 153 ALOGE("Fail to new jbyteArray bd addr for register_notification command"); 154 return; 155 } 156 157 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), 158 (jbyte*)bd_addr.address); 159 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_registerNotification, 160 addr.get(), (jint)event_id, (jint)param); 161 } 162 163 static void btavrcp_volume_change_callback(uint8_t volume, uint8_t ctype, 164 const RawAddress& bd_addr) { 165 CallbackEnv sCallbackEnv(__func__); 166 if (!sCallbackEnv.valid()) return; 167 168 if (!mCallbacksObj) { 169 ALOGE("%s: mCallbacksObj is null", __func__); 170 return; 171 } 172 173 ScopedLocalRef<jbyteArray> addr( 174 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); 175 if (!addr.get()) { 176 ALOGE("Fail to new jbyteArray bd addr for volume_change command"); 177 return; 178 } 179 180 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), 181 (jbyte*)bd_addr.address); 182 183 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_volumeChangeCallback, 184 addr.get(), (jint)volume, (jint)ctype); 185 } 186 187 static void btavrcp_passthrough_command_callback(int id, int pressed, 188 const RawAddress& bd_addr) { 189 CallbackEnv sCallbackEnv(__func__); 190 if (!sCallbackEnv.valid()) return; 191 192 if (!mCallbacksObj) { 193 ALOGE("%s: mCallbacksObj is null", __func__); 194 return; 195 } 196 197 ScopedLocalRef<jbyteArray> addr( 198 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); 199 if (!addr.get()) { 200 ALOGE("Fail to new jbyteArray bd addr for passthrough_command command"); 201 return; 202 } 203 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), 204 (jbyte*)bd_addr.address); 205 206 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handlePassthroughCmd, 207 addr.get(), (jint)id, (jint)pressed); 208 } 209 210 static void btavrcp_set_addressed_player_callback(uint16_t player_id, 211 const RawAddress& bd_addr) { 212 CallbackEnv sCallbackEnv(__func__); 213 if (!sCallbackEnv.valid()) return; 214 215 if (!mCallbacksObj) { 216 ALOGE("%s: mCallbacksObj is null", __func__); 217 return; 218 } 219 220 ScopedLocalRef<jbyteArray> addr( 221 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); 222 if (!addr.get()) { 223 ALOGE("Fail to new jbyteArray bd addr for set_addressed_player command"); 224 return; 225 } 226 227 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), 228 (jbyte*)bd_addr.address); 229 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setAddressedPlayerCallback, 230 addr.get(), (jint)player_id); 231 } 232 233 static void btavrcp_set_browsed_player_callback(uint16_t player_id, 234 const RawAddress& bd_addr) { 235 CallbackEnv sCallbackEnv(__func__); 236 if (!sCallbackEnv.valid()) return; 237 if (!mCallbacksObj) { 238 ALOGE("%s: mCallbacksObj is null", __func__); 239 return; 240 } 241 242 ScopedLocalRef<jbyteArray> addr( 243 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); 244 if (!addr.get()) { 245 ALOGE("Fail to new jbyteArray bd addr for set_browsed_player command"); 246 return; 247 } 248 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), 249 (jbyte*)bd_addr.address); 250 251 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setBrowsedPlayerCallback, 252 addr.get(), (jint)player_id); 253 } 254 255 static void btavrcp_get_folder_items_callback( 256 uint8_t scope, uint32_t start_item, uint32_t end_item, uint8_t num_attr, 257 uint32_t* p_attr_ids, const RawAddress& bd_addr) { 258 CallbackEnv sCallbackEnv(__func__); 259 if (!sCallbackEnv.valid()) return; 260 261 if (!mCallbacksObj) { 262 ALOGE("%s: mCallbacksObj is null", __func__); 263 return; 264 } 265 266 ScopedLocalRef<jbyteArray> addr( 267 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); 268 if (!addr.get()) { 269 ALOGE("Fail to new jbyteArray bd addr for get_folder_items command"); 270 return; 271 } 272 273 uint32_t* puiAttr = (uint32_t*)p_attr_ids; 274 ScopedLocalRef<jintArray> attr_ids(sCallbackEnv.get(), NULL); 275 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), 276 (jbyte*)bd_addr.address); 277 278 /* check number of attributes requested by remote device */ 279 if ((num_attr != BTRC_NUM_ATTR_ALL) && (num_attr != BTRC_NUM_ATTR_NONE)) { 280 /* allocate memory for attr_ids only if some attributes passed from below 281 * layer */ 282 attr_ids.reset((jintArray)sCallbackEnv->NewIntArray(num_attr)); 283 if (!attr_ids.get()) { 284 ALOGE("Fail to allocate new jintArray for attrs"); 285 return; 286 } 287 sCallbackEnv->SetIntArrayRegion(attr_ids.get(), 0, num_attr, 288 (jint*)puiAttr); 289 } 290 291 sCallbackEnv->CallVoidMethod( 292 mCallbacksObj, method_getFolderItemsCallback, addr.get(), (jbyte)scope, 293 (jlong)start_item, (jlong)end_item, (jbyte)num_attr, attr_ids.get()); 294 } 295 296 static void btavrcp_change_path_callback(uint8_t direction, uint8_t* folder_uid, 297 const RawAddress& bd_addr) { 298 CallbackEnv sCallbackEnv(__func__); 299 if (!sCallbackEnv.valid()) return; 300 301 if (!mCallbacksObj) { 302 ALOGE("%s: mCallbacksObj is null", __func__); 303 return; 304 } 305 306 ScopedLocalRef<jbyteArray> attrs(sCallbackEnv.get(), 307 sCallbackEnv->NewByteArray(BTRC_UID_SIZE)); 308 if (!attrs.get()) { 309 ALOGE("Fail to new jintArray for attrs"); 310 return; 311 } 312 313 ScopedLocalRef<jbyteArray> addr( 314 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); 315 if (!addr.get()) { 316 ALOGE("Fail to new jbyteArray bd addr for change_path command"); 317 return; 318 } 319 320 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), 321 (jbyte*)bd_addr.address); 322 sCallbackEnv->SetByteArrayRegion( 323 attrs.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)folder_uid); 324 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_changePathCallback, 325 addr.get(), (jbyte)direction, attrs.get()); 326 } 327 328 static void btavrcp_get_item_attr_callback(uint8_t scope, uint8_t* uid, 329 uint16_t uid_counter, 330 uint8_t num_attr, 331 btrc_media_attr_t* p_attrs, 332 const RawAddress& bd_addr) { 333 CallbackEnv sCallbackEnv(__func__); 334 if (!sCallbackEnv.valid()) return; 335 336 if (!mCallbacksObj) { 337 ALOGE("%s: mCallbacksObj is null", __func__); 338 return; 339 } 340 341 ScopedLocalRef<jbyteArray> attr_uid( 342 sCallbackEnv.get(), sCallbackEnv->NewByteArray(BTRC_UID_SIZE)); 343 if (!attr_uid.get()) { 344 ALOGE("Fail to new jintArray for attr_uid"); 345 return; 346 } 347 348 ScopedLocalRef<jbyteArray> addr( 349 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); 350 if (!addr.get()) { 351 ALOGE("Fail to new jbyteArray bd addr for get_item_attr command"); 352 return; 353 } 354 355 ScopedLocalRef<jintArray> attrs( 356 sCallbackEnv.get(), (jintArray)sCallbackEnv->NewIntArray(num_attr)); 357 if (!attrs.get()) { 358 ALOGE("Fail to new jintArray for attrs"); 359 return; 360 } 361 362 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), 363 (jbyte*)bd_addr.address); 364 sCallbackEnv->SetIntArrayRegion(attrs.get(), 0, num_attr, (jint*)p_attrs); 365 sCallbackEnv->SetByteArrayRegion( 366 attr_uid.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)uid); 367 368 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getItemAttrCallback, 369 addr.get(), (jbyte)scope, attr_uid.get(), 370 (jint)uid_counter, (jbyte)num_attr, attrs.get()); 371 } 372 373 static void btavrcp_play_item_callback(uint8_t scope, uint16_t uid_counter, 374 uint8_t* uid, 375 const RawAddress& bd_addr) { 376 CallbackEnv sCallbackEnv(__func__); 377 if (!sCallbackEnv.valid()) return; 378 if (!mCallbacksObj) { 379 ALOGE("%s: mCallbacksObj is null", __func__); 380 return; 381 } 382 383 ScopedLocalRef<jbyteArray> attrs(sCallbackEnv.get(), 384 sCallbackEnv->NewByteArray(BTRC_UID_SIZE)); 385 if (!attrs.get()) { 386 ALOGE("%s: Fail to new jByteArray attrs for play_item command", __func__); 387 return; 388 } 389 390 ScopedLocalRef<jbyteArray> addr( 391 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); 392 if (!addr.get()) { 393 ALOGE("Fail to new jbyteArray bd addr for play_item command"); 394 return; 395 } 396 397 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), 398 (jbyte*)bd_addr.address); 399 sCallbackEnv->SetByteArrayRegion( 400 attrs.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)uid); 401 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_playItemCallback, 402 addr.get(), (jbyte)scope, (jint)uid_counter, 403 attrs.get()); 404 } 405 406 static void btavrcp_get_total_num_items_callback(uint8_t scope, 407 const RawAddress& bd_addr) { 408 CallbackEnv sCallbackEnv(__func__); 409 if (!sCallbackEnv.valid()) return; 410 if (!mCallbacksObj) { 411 ALOGE("%s: mCallbacksObj is null", __func__); 412 return; 413 } 414 415 ScopedLocalRef<jbyteArray> addr( 416 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); 417 if (!addr.get()) { 418 ALOGE("Fail to new jbyteArray bd addr for get_total_num_items command"); 419 return; 420 } 421 422 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), 423 (jbyte*)bd_addr.address); 424 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getTotalNumOfItemsCallback, 425 addr.get(), (jbyte)scope); 426 } 427 428 static void btavrcp_search_callback(uint16_t charset_id, uint16_t str_len, 429 uint8_t* p_str, const RawAddress& bd_addr) { 430 CallbackEnv sCallbackEnv(__func__); 431 if (!sCallbackEnv.valid()) return; 432 if (!mCallbacksObj) { 433 ALOGE("%s: mCallbacksObj is null", __func__); 434 return; 435 } 436 437 ScopedLocalRef<jbyteArray> attrs(sCallbackEnv.get(), 438 sCallbackEnv->NewByteArray(str_len)); 439 if (!attrs.get()) { 440 ALOGE("Fail to new jintArray for attrs"); 441 return; 442 } 443 444 ScopedLocalRef<jbyteArray> addr( 445 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); 446 if (!addr.get()) { 447 ALOGE("Fail to new jbyteArray bd addr for search command"); 448 return; 449 } 450 451 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), 452 (jbyte*)bd_addr.address); 453 sCallbackEnv->SetByteArrayRegion(attrs.get(), 0, str_len * sizeof(uint8_t), 454 (jbyte*)p_str); 455 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_searchCallback, addr.get(), 456 (jint)charset_id, attrs.get()); 457 } 458 459 static void btavrcp_add_to_play_list_callback(uint8_t scope, uint8_t* uid, 460 uint16_t uid_counter, 461 const RawAddress& bd_addr) { 462 CallbackEnv sCallbackEnv(__func__); 463 if (!sCallbackEnv.valid()) return; 464 if (!mCallbacksObj) { 465 ALOGE("%s: mCallbacksObj is null", __func__); 466 return; 467 } 468 469 ScopedLocalRef<jbyteArray> addr( 470 sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress))); 471 if (!addr.get()) { 472 ALOGE("Fail to new jbyteArray bd addr for add_to_play_list command"); 473 return; 474 } 475 476 ScopedLocalRef<jbyteArray> attrs(sCallbackEnv.get(), 477 sCallbackEnv->NewByteArray(BTRC_UID_SIZE)); 478 if (!attrs.get()) { 479 ALOGE("Fail to new jByteArray for attrs"); 480 return; 481 } 482 483 sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), 484 (jbyte*)bd_addr.address); 485 sCallbackEnv->SetByteArrayRegion( 486 attrs.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)uid); 487 sCallbackEnv->CallVoidMethod(mCallbacksObj, method_addToPlayListCallback, 488 addr.get(), (jbyte)scope, attrs.get(), 489 (jint)uid_counter); 490 } 491 492 static btrc_callbacks_t sBluetoothAvrcpCallbacks = { 493 sizeof(sBluetoothAvrcpCallbacks), 494 btavrcp_remote_features_callback, 495 btavrcp_get_play_status_callback, 496 NULL, 497 NULL, 498 NULL, 499 NULL, 500 NULL, 501 NULL, 502 btavrcp_get_element_attr_callback, 503 btavrcp_register_notification_callback, 504 btavrcp_volume_change_callback, 505 btavrcp_passthrough_command_callback, 506 btavrcp_set_addressed_player_callback, 507 btavrcp_set_browsed_player_callback, 508 btavrcp_get_folder_items_callback, 509 btavrcp_change_path_callback, 510 btavrcp_get_item_attr_callback, 511 btavrcp_play_item_callback, 512 btavrcp_get_total_num_items_callback, 513 btavrcp_search_callback, 514 btavrcp_add_to_play_list_callback, 515 }; 516 517 static void classInitNative(JNIEnv* env, jclass clazz) { 518 method_getRcFeatures = 519 env->GetMethodID(clazz, "getRcFeaturesRequestFromNative", "([BI)V"); 520 method_getPlayStatus = 521 env->GetMethodID(clazz, "getPlayStatusRequestFromNative", "([B)V"); 522 523 method_getElementAttr = 524 env->GetMethodID(clazz, "getElementAttrRequestFromNative", "([BB[I)V"); 525 526 method_registerNotification = env->GetMethodID( 527 clazz, "registerNotificationRequestFromNative", "([BII)V"); 528 529 method_volumeChangeCallback = 530 env->GetMethodID(clazz, "volumeChangeRequestFromNative", "([BII)V"); 531 532 method_handlePassthroughCmd = env->GetMethodID( 533 clazz, "handlePassthroughCmdRequestFromNative", "([BII)V"); 534 535 method_setAddressedPlayerCallback = 536 env->GetMethodID(clazz, "setAddressedPlayerRequestFromNative", "([BI)V"); 537 538 method_setBrowsedPlayerCallback = 539 env->GetMethodID(clazz, "setBrowsedPlayerRequestFromNative", "([BI)V"); 540 541 method_getFolderItemsCallback = 542 env->GetMethodID(clazz, "getFolderItemsRequestFromNative", "([BBJJB[I)V"); 543 544 method_changePathCallback = 545 env->GetMethodID(clazz, "changePathRequestFromNative", "([BB[B)V"); 546 547 method_getItemAttrCallback = 548 env->GetMethodID(clazz, "getItemAttrRequestFromNative", "([BB[BIB[I)V"); 549 550 method_playItemCallback = 551 env->GetMethodID(clazz, "playItemRequestFromNative", "([BBI[B)V"); 552 553 method_getTotalNumOfItemsCallback = 554 env->GetMethodID(clazz, "getTotalNumOfItemsRequestFromNative", "([BB)V"); 555 556 method_searchCallback = 557 env->GetMethodID(clazz, "searchRequestFromNative", "([BI[B)V"); 558 559 method_addToPlayListCallback = 560 env->GetMethodID(clazz, "addToPlayListRequestFromNative", "([BB[BI)V"); 561 562 ALOGI("%s: succeeds", __func__); 563 } 564 565 static void initNative(JNIEnv* env, jobject object) { 566 const bt_interface_t* btInf = getBluetoothInterface(); 567 if (btInf == NULL) { 568 ALOGE("Bluetooth module is not loaded"); 569 return; 570 } 571 572 if (sBluetoothAvrcpInterface != NULL) { 573 ALOGW("Cleaning up Avrcp Interface before initializing..."); 574 sBluetoothAvrcpInterface->cleanup(); 575 sBluetoothAvrcpInterface = NULL; 576 } 577 578 if (mCallbacksObj != NULL) { 579 ALOGW("Cleaning up Avrcp callback object"); 580 env->DeleteGlobalRef(mCallbacksObj); 581 mCallbacksObj = NULL; 582 } 583 584 sBluetoothAvrcpInterface = 585 (btrc_interface_t*)btInf->get_profile_interface(BT_PROFILE_AV_RC_ID); 586 if (sBluetoothAvrcpInterface == NULL) { 587 ALOGE("Failed to get Bluetooth Avrcp Interface"); 588 return; 589 } 590 591 bt_status_t status = 592 sBluetoothAvrcpInterface->init(&sBluetoothAvrcpCallbacks); 593 if (status != BT_STATUS_SUCCESS) { 594 ALOGE("Failed to initialize Bluetooth Avrcp, status: %d", status); 595 sBluetoothAvrcpInterface = NULL; 596 return; 597 } 598 599 mCallbacksObj = env->NewGlobalRef(object); 600 } 601 602 static void cleanupNative(JNIEnv* env, jobject object) { 603 const bt_interface_t* btInf = getBluetoothInterface(); 604 if (btInf == NULL) { 605 ALOGE("Bluetooth module is not loaded"); 606 return; 607 } 608 609 if (sBluetoothAvrcpInterface != NULL) { 610 sBluetoothAvrcpInterface->cleanup(); 611 sBluetoothAvrcpInterface = NULL; 612 } 613 614 if (mCallbacksObj != NULL) { 615 env->DeleteGlobalRef(mCallbacksObj); 616 mCallbacksObj = NULL; 617 } 618 } 619 620 static jboolean getPlayStatusRspNative(JNIEnv* env, jobject object, 621 jbyteArray address, jint playStatus, 622 jint songLen, jint songPos) { 623 if (!sBluetoothAvrcpInterface) { 624 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 625 return JNI_FALSE; 626 } 627 628 jbyte* addr = env->GetByteArrayElements(address, NULL); 629 if (!addr) { 630 jniThrowIOException(env, EINVAL); 631 return JNI_FALSE; 632 } 633 RawAddress rawAddress; 634 rawAddress.FromOctets((uint8_t*)addr); 635 636 bt_status_t status = sBluetoothAvrcpInterface->get_play_status_rsp( 637 rawAddress, (btrc_play_status_t)playStatus, songLen, songPos); 638 if (status != BT_STATUS_SUCCESS) { 639 ALOGE("Failed get_play_status_rsp, status: %d", status); 640 } 641 env->ReleaseByteArrayElements(address, addr, 0); 642 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 643 } 644 645 static jboolean getElementAttrRspNative(JNIEnv* env, jobject object, 646 jbyteArray address, jbyte numAttr, 647 jintArray attrIds, 648 jobjectArray textArray) { 649 if (!sBluetoothAvrcpInterface) { 650 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 651 return JNI_FALSE; 652 } 653 654 if (numAttr > BTRC_MAX_ELEM_ATTR_SIZE) { 655 ALOGE("get_element_attr_rsp: number of attributes exceed maximum"); 656 return JNI_FALSE; 657 } 658 659 jbyte* addr = env->GetByteArrayElements(address, NULL); 660 if (!addr) { 661 jniThrowIOException(env, EINVAL); 662 return JNI_FALSE; 663 } 664 665 btrc_element_attr_val_t* pAttrs = new btrc_element_attr_val_t[numAttr]; 666 if (!pAttrs) { 667 ALOGE("get_element_attr_rsp: not have enough memeory"); 668 env->ReleaseByteArrayElements(address, addr, 0); 669 return JNI_FALSE; 670 } 671 672 jint* attr = env->GetIntArrayElements(attrIds, NULL); 673 if (!attr) { 674 delete[] pAttrs; 675 jniThrowIOException(env, EINVAL); 676 env->ReleaseByteArrayElements(address, addr, 0); 677 return JNI_FALSE; 678 } 679 680 int attr_cnt; 681 for (attr_cnt = 0; attr_cnt < numAttr; ++attr_cnt) { 682 pAttrs[attr_cnt].attr_id = attr[attr_cnt]; 683 ScopedLocalRef<jstring> text( 684 env, (jstring)env->GetObjectArrayElement(textArray, attr_cnt)); 685 686 if (!copy_jstring(pAttrs[attr_cnt].text, BTRC_MAX_ATTR_STR_LEN, text.get(), 687 env)) { 688 break; 689 } 690 } 691 692 if (attr_cnt < numAttr) { 693 delete[] pAttrs; 694 env->ReleaseIntArrayElements(attrIds, attr, 0); 695 ALOGE("%s: Failed to copy attributes", __func__); 696 return JNI_FALSE; 697 } 698 699 RawAddress rawAddress; 700 rawAddress.FromOctets((uint8_t*)addr); 701 bt_status_t status = sBluetoothAvrcpInterface->get_element_attr_rsp( 702 rawAddress, numAttr, pAttrs); 703 if (status != BT_STATUS_SUCCESS) { 704 ALOGE("Failed get_element_attr_rsp, status: %d", status); 705 } 706 707 delete[] pAttrs; 708 env->ReleaseIntArrayElements(attrIds, attr, 0); 709 env->ReleaseByteArrayElements(address, addr, 0); 710 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 711 } 712 713 static jboolean getItemAttrRspNative(JNIEnv* env, jobject object, 714 jbyteArray address, jint rspStatus, 715 jbyte numAttr, jintArray attrIds, 716 jobjectArray textArray) { 717 if (!sBluetoothAvrcpInterface) { 718 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 719 return JNI_FALSE; 720 } 721 722 jbyte* addr = env->GetByteArrayElements(address, NULL); 723 if (!addr) { 724 jniThrowIOException(env, EINVAL); 725 return JNI_FALSE; 726 } 727 728 if (numAttr > BTRC_MAX_ELEM_ATTR_SIZE) { 729 ALOGE("get_element_attr_rsp: number of attributes exceed maximum"); 730 return JNI_FALSE; 731 } 732 733 btrc_element_attr_val_t* pAttrs = new btrc_element_attr_val_t[numAttr]; 734 if (!pAttrs) { 735 ALOGE("%s: not have enough memory", __func__); 736 env->ReleaseByteArrayElements(address, addr, 0); 737 return JNI_FALSE; 738 } 739 740 jint* attr = NULL; 741 if (attrIds != NULL) { 742 attr = env->GetIntArrayElements(attrIds, NULL); 743 if (!attr) { 744 delete[] pAttrs; 745 jniThrowIOException(env, EINVAL); 746 env->ReleaseByteArrayElements(address, addr, 0); 747 return JNI_FALSE; 748 } 749 } 750 751 for (int attr_cnt = 0; attr_cnt < numAttr; ++attr_cnt) { 752 pAttrs[attr_cnt].attr_id = attr[attr_cnt]; 753 ScopedLocalRef<jstring> text( 754 env, (jstring)env->GetObjectArrayElement(textArray, attr_cnt)); 755 756 if (!copy_jstring(pAttrs[attr_cnt].text, BTRC_MAX_ATTR_STR_LEN, text.get(), 757 env)) { 758 rspStatus = BTRC_STS_INTERNAL_ERR; 759 ALOGE("%s: Failed to copy attributes", __func__); 760 break; 761 } 762 } 763 RawAddress rawAddress; 764 rawAddress.FromOctets((uint8_t*)addr); 765 766 bt_status_t status = sBluetoothAvrcpInterface->get_item_attr_rsp( 767 rawAddress, (btrc_status_t)rspStatus, numAttr, pAttrs); 768 if (status != BT_STATUS_SUCCESS) 769 ALOGE("Failed get_item_attr_rsp, status: %d", status); 770 771 if (pAttrs) delete[] pAttrs; 772 if (attr) env->ReleaseIntArrayElements(attrIds, attr, 0); 773 env->ReleaseByteArrayElements(address, addr, 0); 774 775 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 776 } 777 778 static jboolean registerNotificationRspPlayStatusNative(JNIEnv* env, 779 jobject object, 780 jint type, 781 jint playStatus) { 782 if (!sBluetoothAvrcpInterface) { 783 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 784 return JNI_FALSE; 785 } 786 787 btrc_register_notification_t param; 788 param.play_status = (btrc_play_status_t)playStatus; 789 790 bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp( 791 BTRC_EVT_PLAY_STATUS_CHANGED, (btrc_notification_type_t)type, ¶m); 792 if (status != BT_STATUS_SUCCESS) { 793 ALOGE("Failed register_notification_rsp play status, status: %d", status); 794 } 795 796 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 797 } 798 799 static jboolean registerNotificationRspTrackChangeNative(JNIEnv* env, 800 jobject object, 801 jint type, 802 jbyteArray track) { 803 if (!sBluetoothAvrcpInterface) { 804 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 805 return JNI_FALSE; 806 } 807 808 jbyte* trk = env->GetByteArrayElements(track, NULL); 809 if (!trk) { 810 jniThrowIOException(env, EINVAL); 811 return JNI_FALSE; 812 } 813 814 btrc_register_notification_t param; 815 uint64_t uid = 0; 816 for (int uid_idx = 0; uid_idx < BTRC_UID_SIZE; ++uid_idx) { 817 param.track[uid_idx] = trk[uid_idx]; 818 uid = uid + (trk[uid_idx] << (BTRC_UID_SIZE - 1 - uid_idx)); 819 } 820 821 ALOGV("%s: Sending track change notification: %d -> %" PRIu64, __func__, type, 822 uid); 823 824 bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp( 825 BTRC_EVT_TRACK_CHANGE, (btrc_notification_type_t)type, ¶m); 826 if (status != BT_STATUS_SUCCESS) { 827 ALOGE("Failed register_notification_rsp track change, status: %d", status); 828 } 829 830 env->ReleaseByteArrayElements(track, trk, 0); 831 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 832 } 833 834 static jboolean registerNotificationRspPlayPosNative(JNIEnv* env, 835 jobject object, jint type, 836 jint playPos) { 837 if (!sBluetoothAvrcpInterface) { 838 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 839 return JNI_FALSE; 840 } 841 842 btrc_register_notification_t param; 843 param.song_pos = (uint32_t)playPos; 844 845 bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp( 846 BTRC_EVT_PLAY_POS_CHANGED, (btrc_notification_type_t)type, ¶m); 847 if (status != BT_STATUS_SUCCESS) { 848 ALOGE("Failed register_notification_rsp play position, status: %d", status); 849 } 850 851 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 852 } 853 854 static jboolean registerNotificationRspNowPlayingChangedNative(JNIEnv* env, 855 jobject object, 856 jint type) { 857 if (!sBluetoothAvrcpInterface) { 858 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 859 return JNI_FALSE; 860 } 861 862 btrc_register_notification_t param; 863 bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp( 864 BTRC_EVT_NOW_PLAYING_CONTENT_CHANGED, (btrc_notification_type_t)type, 865 ¶m); 866 if (status != BT_STATUS_SUCCESS) { 867 ALOGE("Failed register_notification_rsp, nowPlaying Content status: %d", 868 status); 869 } 870 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 871 } 872 873 static jboolean registerNotificationRspUIDsChangedNative(JNIEnv* env, 874 jobject object, 875 jint type, 876 jint uidCounter) { 877 if (!sBluetoothAvrcpInterface) { 878 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 879 return JNI_FALSE; 880 } 881 882 btrc_register_notification_t param; 883 param.uids_changed.uid_counter = (uint16_t)uidCounter; 884 885 bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp( 886 BTRC_EVT_UIDS_CHANGED, (btrc_notification_type_t)type, ¶m); 887 if (status != BT_STATUS_SUCCESS) { 888 ALOGE("Failed register_notification_rsp, uids changed status: %d", status); 889 } 890 891 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 892 } 893 894 static jboolean registerNotificationRspAddrPlayerChangedNative( 895 JNIEnv* env, jobject object, jint type, jint playerId, jint uidCounter) { 896 if (!sBluetoothAvrcpInterface) { 897 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 898 return JNI_FALSE; 899 } 900 901 btrc_register_notification_t param; 902 param.addr_player_changed.player_id = (uint16_t)playerId; 903 param.addr_player_changed.uid_counter = (uint16_t)uidCounter; 904 905 bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp( 906 BTRC_EVT_ADDR_PLAYER_CHANGE, (btrc_notification_type_t)type, ¶m); 907 if (status != BT_STATUS_SUCCESS) { 908 ALOGE("Failed register_notification_rsp address player changed status: %d", 909 status); 910 } 911 912 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 913 } 914 915 static jboolean registerNotificationRspAvalPlayerChangedNative(JNIEnv* env, 916 jobject object, 917 jint type) { 918 if (!sBluetoothAvrcpInterface) { 919 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 920 return JNI_FALSE; 921 } 922 923 btrc_register_notification_t param; 924 bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp( 925 BTRC_EVT_AVAL_PLAYER_CHANGE, (btrc_notification_type_t)type, ¶m); 926 if (status != BT_STATUS_SUCCESS) { 927 ALOGE( 928 "Failed register_notification_rsp available player changed status, " 929 "status: %d", 930 status); 931 } 932 933 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 934 } 935 936 static jboolean setVolumeNative(JNIEnv* env, jobject object, jint volume) { 937 if (!sBluetoothAvrcpInterface) { 938 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 939 return JNI_FALSE; 940 } 941 942 bt_status_t status = sBluetoothAvrcpInterface->set_volume((uint8_t)volume); 943 if (status != BT_STATUS_SUCCESS) { 944 ALOGE("Failed set_volume, status: %d", status); 945 } 946 947 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 948 } 949 950 /* native response for scope as Media player */ 951 static jboolean mediaPlayerListRspNative( 952 JNIEnv* env, jobject object, jbyteArray address, jint rspStatus, 953 jint uidCounter, jbyte itemType, jint numItems, jintArray playerIds, 954 jbyteArray playerTypes, jintArray playerSubtypes, 955 jbyteArray playStatusValues, jshortArray featureBitmask, 956 jobjectArray textArray) { 957 if (!sBluetoothAvrcpInterface) { 958 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 959 return JNI_FALSE; 960 } 961 962 jbyte* addr = env->GetByteArrayElements(address, NULL); 963 if (!addr) { 964 jniThrowIOException(env, EINVAL); 965 return JNI_FALSE; 966 } 967 968 jbyte *p_playerTypes = NULL, *p_PlayStatusValues = NULL; 969 jshort* p_FeatBitMaskValues = NULL; 970 jint *p_playerIds = NULL, *p_playerSubTypes = NULL; 971 btrc_folder_items_t* p_items = NULL; 972 if (rspStatus == BTRC_STS_NO_ERROR) { 973 /* allocate memory */ 974 p_playerIds = env->GetIntArrayElements(playerIds, NULL); 975 p_playerTypes = env->GetByteArrayElements(playerTypes, NULL); 976 p_playerSubTypes = env->GetIntArrayElements(playerSubtypes, NULL); 977 p_PlayStatusValues = env->GetByteArrayElements(playStatusValues, NULL); 978 p_FeatBitMaskValues = env->GetShortArrayElements(featureBitmask, NULL); 979 p_items = new btrc_folder_items_t[numItems]; 980 /* deallocate memory and return if allocation failed */ 981 if (!p_playerIds || !p_playerTypes || !p_playerSubTypes || 982 !p_PlayStatusValues || !p_FeatBitMaskValues || !p_items) { 983 if (p_playerIds) env->ReleaseIntArrayElements(playerIds, p_playerIds, 0); 984 if (p_playerTypes) 985 env->ReleaseByteArrayElements(playerTypes, p_playerTypes, 0); 986 if (p_playerSubTypes) 987 env->ReleaseIntArrayElements(playerSubtypes, p_playerSubTypes, 0); 988 if (p_PlayStatusValues) 989 env->ReleaseByteArrayElements(playStatusValues, p_PlayStatusValues, 0); 990 if (p_FeatBitMaskValues) 991 env->ReleaseShortArrayElements(featureBitmask, p_FeatBitMaskValues, 0); 992 if (p_items) delete[] p_items; 993 994 jniThrowIOException(env, EINVAL); 995 ALOGE("%s: not have enough memory", __func__); 996 return JNI_FALSE; 997 } 998 999 p_items->item_type = (uint8_t)itemType; 1000 1001 /* copy list of media players along with other parameters */ 1002 int itemIdx; 1003 for (itemIdx = 0; itemIdx < numItems; ++itemIdx) { 1004 p_items[itemIdx].player.player_id = p_playerIds[itemIdx]; 1005 p_items[itemIdx].player.major_type = p_playerTypes[itemIdx]; 1006 p_items[itemIdx].player.sub_type = p_playerSubTypes[itemIdx]; 1007 p_items[itemIdx].player.play_status = p_PlayStatusValues[itemIdx]; 1008 p_items[itemIdx].player.charset_id = BTRC_CHARSET_ID_UTF8; 1009 1010 ScopedLocalRef<jstring> text( 1011 env, (jstring)env->GetObjectArrayElement(textArray, itemIdx)); 1012 /* copy player name */ 1013 if (!copy_jstring(p_items[itemIdx].player.name, BTRC_MAX_ATTR_STR_LEN, 1014 text.get(), env)) 1015 break; 1016 1017 /* Feature bit mask is 128-bit value each */ 1018 for (int InnCnt = 0; InnCnt < 16; InnCnt++) { 1019 p_items[itemIdx].player.features[InnCnt] = 1020 (uint8_t)p_FeatBitMaskValues[(itemIdx * 16) + InnCnt]; 1021 } 1022 } 1023 1024 /* failed to copy list of media players */ 1025 if (itemIdx < numItems) { 1026 rspStatus = BTRC_STS_INTERNAL_ERR; 1027 ALOGE("%s: Failed to copy Media player attributes", __func__); 1028 } 1029 } 1030 1031 RawAddress* btAddr = (RawAddress*)addr; 1032 bt_status_t status = sBluetoothAvrcpInterface->get_folder_items_list_rsp( 1033 *btAddr, (btrc_status_t)rspStatus, uidCounter, numItems, p_items); 1034 if (status != BT_STATUS_SUCCESS) { 1035 ALOGE("Failed get_folder_items_list_rsp, status: %d", status); 1036 } 1037 1038 /* release allocated memory */ 1039 if (p_items) delete[] p_items; 1040 if (p_playerTypes) 1041 env->ReleaseByteArrayElements(playerTypes, p_playerTypes, 0); 1042 if (p_playerSubTypes) 1043 env->ReleaseIntArrayElements(playerSubtypes, p_playerSubTypes, 0); 1044 if (p_PlayStatusValues) 1045 env->ReleaseByteArrayElements(playStatusValues, p_PlayStatusValues, 0); 1046 if (p_FeatBitMaskValues) { 1047 env->ReleaseShortArrayElements(featureBitmask, p_FeatBitMaskValues, 0); 1048 } 1049 env->ReleaseByteArrayElements(address, addr, 0); 1050 1051 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 1052 } 1053 1054 static jboolean getFolderItemsRspNative( 1055 JNIEnv* env, jobject object, jbyteArray address, jint rspStatus, 1056 jshort uidCounter, jbyte scope, jint numItems, jbyteArray folderType, 1057 jbyteArray playable, jbyteArray itemType, jbyteArray itemUidArray, 1058 jobjectArray displayNameArray, jintArray numAttrs, jintArray attributesIds, 1059 jobjectArray attributesArray) { 1060 if (!sBluetoothAvrcpInterface) { 1061 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 1062 return JNI_FALSE; 1063 } 1064 1065 jbyte* addr = env->GetByteArrayElements(address, NULL); 1066 if (!addr) { 1067 jniThrowIOException(env, EINVAL); 1068 return JNI_FALSE; 1069 } 1070 1071 jbyte *p_playable = NULL, *p_item_uid = NULL; 1072 jbyte* p_item_types = NULL; /* Folder or Media Item */ 1073 jint* p_attributesIds = NULL; 1074 jbyte* p_folder_types = 1075 NULL; /* Folder properties like Album/Genre/Artists etc */ 1076 jint* p_num_attrs = NULL; 1077 btrc_folder_items_t* p_items = NULL; 1078 /* none of the parameters should be null when no error */ 1079 if (rspStatus == BTRC_STS_NO_ERROR) { 1080 /* allocate memory to each rsp item */ 1081 if (folderType != NULL) 1082 p_folder_types = env->GetByteArrayElements(folderType, NULL); 1083 if (playable != NULL) 1084 p_playable = env->GetByteArrayElements(playable, NULL); 1085 if (itemType != NULL) 1086 p_item_types = env->GetByteArrayElements(itemType, NULL); 1087 if (NULL != numAttrs) 1088 p_num_attrs = env->GetIntArrayElements(numAttrs, NULL); 1089 if (NULL != attributesIds) 1090 p_attributesIds = env->GetIntArrayElements(attributesIds, NULL); 1091 if (itemUidArray != NULL) 1092 p_item_uid = (jbyte*)env->GetByteArrayElements(itemUidArray, NULL); 1093 1094 p_items = new btrc_folder_items_t[numItems]; 1095 1096 /* if memory alloc failed, release memory */ 1097 if (p_items && p_folder_types && p_playable && p_item_types && p_item_uid && 1098 /* attributes can be null if remote requests 0 attributes */ 1099 ((numAttrs != NULL && p_num_attrs) || (!numAttrs && !p_num_attrs)) && 1100 ((attributesIds != NULL && p_attributesIds) || 1101 (!attributesIds && !p_attributesIds))) { 1102 memset(p_items, 0, sizeof(btrc_folder_items_t) * numItems); 1103 if (scope == BTRC_SCOPE_FILE_SYSTEM || scope == BTRC_SCOPE_SEARCH || 1104 scope == BTRC_SCOPE_NOW_PLAYING) { 1105 int attribCopiedIndex = 0; 1106 for (int item_idx = 0; item_idx < numItems; item_idx++) { 1107 if (BTRC_ITEM_FOLDER == p_item_types[item_idx]) { 1108 btrc_folder_items_t* pitem = &p_items[item_idx]; 1109 1110 memcpy(pitem->folder.uid, p_item_uid + item_idx * BTRC_UID_SIZE, 1111 BTRC_UID_SIZE); 1112 pitem->item_type = (uint8_t)BTRC_ITEM_FOLDER; 1113 pitem->folder.charset_id = BTRC_CHARSET_ID_UTF8; 1114 pitem->folder.type = p_folder_types[item_idx]; 1115 pitem->folder.playable = p_playable[item_idx]; 1116 1117 ScopedLocalRef<jstring> text( 1118 env, (jstring)env->GetObjectArrayElement(displayNameArray, 1119 item_idx)); 1120 if (!copy_jstring(pitem->folder.name, BTRC_MAX_ATTR_STR_LEN, 1121 text.get(), env)) { 1122 rspStatus = BTRC_STS_INTERNAL_ERR; 1123 ALOGE("%s: failed to copy display name of folder item", __func__); 1124 break; 1125 } 1126 } else if (BTRC_ITEM_MEDIA == p_item_types[item_idx]) { 1127 btrc_folder_items_t* pitem = &p_items[item_idx]; 1128 memcpy(pitem->media.uid, p_item_uid + item_idx * BTRC_UID_SIZE, 1129 BTRC_UID_SIZE); 1130 1131 pitem->item_type = (uint8_t)BTRC_ITEM_MEDIA; 1132 pitem->media.charset_id = BTRC_CHARSET_ID_UTF8; 1133 pitem->media.type = BTRC_MEDIA_TYPE_AUDIO; 1134 pitem->media.num_attrs = 1135 (p_num_attrs != NULL) ? p_num_attrs[item_idx] : 0; 1136 1137 ScopedLocalRef<jstring> text( 1138 env, (jstring)env->GetObjectArrayElement(displayNameArray, 1139 item_idx)); 1140 if (!copy_jstring(pitem->media.name, BTRC_MAX_ATTR_STR_LEN, 1141 text.get(), env)) { 1142 rspStatus = BTRC_STS_INTERNAL_ERR; 1143 ALOGE("%s: failed to copy display name of media item", __func__); 1144 break; 1145 } 1146 1147 /* copy item attributes */ 1148 if (!copy_item_attributes(env, object, pitem, p_attributesIds, 1149 attributesArray, item_idx, 1150 attribCopiedIndex)) { 1151 ALOGE("%s: error in copying attributes of item = %s", __func__, 1152 pitem->media.name); 1153 rspStatus = BTRC_STS_INTERNAL_ERR; 1154 break; 1155 } 1156 attribCopiedIndex += pitem->media.num_attrs; 1157 } 1158 } 1159 } 1160 } else { 1161 rspStatus = BTRC_STS_INTERNAL_ERR; 1162 ALOGE("%s: unable to allocate memory", __func__); 1163 } 1164 } 1165 1166 RawAddress* btAddr = (RawAddress*)addr; 1167 bt_status_t status = sBluetoothAvrcpInterface->get_folder_items_list_rsp( 1168 *btAddr, (btrc_status_t)rspStatus, uidCounter, numItems, p_items); 1169 if (status != BT_STATUS_SUCCESS) 1170 ALOGE("Failed get_folder_items_list_rsp, status: %d", status); 1171 1172 /* Release allocated memory for all attributes in each media item */ 1173 if (p_items) cleanup_items(p_items, numItems); 1174 1175 /* Release allocated memory */ 1176 if (p_folder_types) 1177 env->ReleaseByteArrayElements(folderType, p_folder_types, 0); 1178 if (p_playable) env->ReleaseByteArrayElements(playable, p_playable, 0); 1179 if (p_item_types) env->ReleaseByteArrayElements(itemType, p_item_types, 0); 1180 if (p_num_attrs) env->ReleaseIntArrayElements(numAttrs, p_num_attrs, 0); 1181 if (p_attributesIds) 1182 env->ReleaseIntArrayElements(attributesIds, p_attributesIds, 0); 1183 if (p_item_uid) env->ReleaseByteArrayElements(itemUidArray, p_item_uid, 0); 1184 if (p_items) delete[] p_items; 1185 env->ReleaseByteArrayElements(address, addr, 0); 1186 1187 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 1188 } 1189 1190 static jboolean setAddressedPlayerRspNative(JNIEnv* env, jobject object, 1191 jbyteArray address, 1192 jint rspStatus) { 1193 if (!sBluetoothAvrcpInterface) { 1194 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 1195 return JNI_FALSE; 1196 } 1197 1198 jbyte* addr = env->GetByteArrayElements(address, NULL); 1199 if (!addr) { 1200 jniThrowIOException(env, EINVAL); 1201 return JNI_FALSE; 1202 } 1203 1204 RawAddress* btAddr = (RawAddress*)addr; 1205 bt_status_t status = sBluetoothAvrcpInterface->set_addressed_player_rsp( 1206 *btAddr, (btrc_status_t)rspStatus); 1207 if (status != BT_STATUS_SUCCESS) { 1208 ALOGE("Failed set_addressed_player_rsp, status: %d", status); 1209 } 1210 env->ReleaseByteArrayElements(address, addr, 0); 1211 1212 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 1213 } 1214 1215 static jboolean setBrowsedPlayerRspNative(JNIEnv* env, jobject object, 1216 jbyteArray address, jint rspStatus, 1217 jbyte depth, jint numItems, 1218 jobjectArray textArray) { 1219 if (!sBluetoothAvrcpInterface) { 1220 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 1221 return JNI_FALSE; 1222 } 1223 1224 jbyte* addr = env->GetByteArrayElements(address, NULL); 1225 if (!addr) { 1226 jniThrowIOException(env, EINVAL); 1227 return JNI_FALSE; 1228 } 1229 1230 btrc_br_folder_name_t* p_folders = NULL; 1231 if (rspStatus == BTRC_STS_NO_ERROR) { 1232 if (depth > 0) { 1233 p_folders = new btrc_br_folder_name_t[depth]; 1234 } 1235 1236 for (int folder_idx = 0; folder_idx < depth; folder_idx++) { 1237 /* copy folder names */ 1238 ScopedLocalRef<jstring> text( 1239 env, (jstring)env->GetObjectArrayElement(textArray, folder_idx)); 1240 1241 if (!copy_jstring(p_folders[folder_idx].p_str, BTRC_MAX_ATTR_STR_LEN, 1242 text.get(), env)) { 1243 rspStatus = BTRC_STS_INTERNAL_ERR; 1244 delete[] p_folders; 1245 env->ReleaseByteArrayElements(address, addr, 0); 1246 ALOGE("%s: Failed to copy folder name", __func__); 1247 return JNI_FALSE; 1248 } 1249 1250 p_folders[folder_idx].str_len = 1251 strlen((char*)p_folders[folder_idx].p_str); 1252 } 1253 } 1254 1255 uint8_t folder_depth = 1256 depth; /* folder_depth is 0 if current folder is root */ 1257 uint16_t charset_id = BTRC_CHARSET_ID_UTF8; 1258 RawAddress* btAddr = (RawAddress*)addr; 1259 bt_status_t status = sBluetoothAvrcpInterface->set_browsed_player_rsp( 1260 *btAddr, (btrc_status_t)rspStatus, numItems, charset_id, folder_depth, 1261 p_folders); 1262 if (status != BT_STATUS_SUCCESS) { 1263 ALOGE("%s: Failed set_browsed_player_rsp, status: %d", __func__, status); 1264 } 1265 1266 if (depth > 0) { 1267 delete[] p_folders; 1268 } 1269 1270 env->ReleaseByteArrayElements(address, addr, 0); 1271 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 1272 } 1273 1274 static jboolean changePathRspNative(JNIEnv* env, jobject object, 1275 jbyteArray address, jint rspStatus, 1276 jint numItems) { 1277 if (!sBluetoothAvrcpInterface) { 1278 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 1279 return JNI_FALSE; 1280 } 1281 1282 jbyte* addr = env->GetByteArrayElements(address, NULL); 1283 if (!addr) { 1284 jniThrowIOException(env, EINVAL); 1285 return JNI_FALSE; 1286 } 1287 1288 uint32_t nItems = (uint32_t)numItems; 1289 RawAddress* btAddr = (RawAddress*)addr; 1290 bt_status_t status = sBluetoothAvrcpInterface->change_path_rsp( 1291 *btAddr, (btrc_status_t)rspStatus, (uint32_t)nItems); 1292 if (status != BT_STATUS_SUCCESS) { 1293 ALOGE("Failed change_path_rsp, status: %d", status); 1294 } 1295 env->ReleaseByteArrayElements(address, addr, 0); 1296 1297 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 1298 } 1299 1300 static jboolean searchRspNative(JNIEnv* env, jobject object, jbyteArray address, 1301 jint rspStatus, jint uidCounter, 1302 jint numItems) { 1303 if (!sBluetoothAvrcpInterface) { 1304 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 1305 return JNI_FALSE; 1306 } 1307 1308 jbyte* addr = env->GetByteArrayElements(address, NULL); 1309 if (!addr) { 1310 jniThrowIOException(env, EINVAL); 1311 return JNI_FALSE; 1312 } 1313 1314 uint32_t nItems = (uint32_t)numItems; 1315 RawAddress* btAddr = (RawAddress*)addr; 1316 bt_status_t status = sBluetoothAvrcpInterface->search_rsp( 1317 *btAddr, (btrc_status_t)rspStatus, (uint32_t)uidCounter, 1318 (uint32_t)nItems); 1319 if (status != BT_STATUS_SUCCESS) { 1320 ALOGE("Failed search_rsp, status: %d", status); 1321 } 1322 1323 env->ReleaseByteArrayElements(address, addr, 0); 1324 1325 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 1326 } 1327 1328 static jboolean playItemRspNative(JNIEnv* env, jobject object, 1329 jbyteArray address, jint rspStatus) { 1330 if (!sBluetoothAvrcpInterface) { 1331 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 1332 return JNI_FALSE; 1333 } 1334 1335 jbyte* addr = env->GetByteArrayElements(address, NULL); 1336 if (!addr) { 1337 jniThrowIOException(env, EINVAL); 1338 return JNI_FALSE; 1339 } 1340 1341 RawAddress* btAddr = (RawAddress*)addr; 1342 bt_status_t status = sBluetoothAvrcpInterface->play_item_rsp( 1343 *btAddr, (btrc_status_t)rspStatus); 1344 if (status != BT_STATUS_SUCCESS) { 1345 ALOGE("Failed play_item_rsp, status: %d", status); 1346 } 1347 env->ReleaseByteArrayElements(address, addr, 0); 1348 1349 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 1350 } 1351 1352 static jboolean getTotalNumOfItemsRspNative(JNIEnv* env, jobject object, 1353 jbyteArray address, jint rspStatus, 1354 jint uidCounter, jint numItems) { 1355 if (!sBluetoothAvrcpInterface) { 1356 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 1357 return JNI_FALSE; 1358 } 1359 1360 jbyte* addr = env->GetByteArrayElements(address, NULL); 1361 if (!addr) { 1362 jniThrowIOException(env, EINVAL); 1363 return JNI_FALSE; 1364 } 1365 1366 uint32_t nItems = (uint32_t)numItems; 1367 RawAddress* btAddr = (RawAddress*)addr; 1368 bt_status_t status = sBluetoothAvrcpInterface->get_total_num_of_items_rsp( 1369 *btAddr, (btrc_status_t)rspStatus, (uint32_t)uidCounter, 1370 (uint32_t)nItems); 1371 if (status != BT_STATUS_SUCCESS) { 1372 ALOGE("Failed get_total_num_of_items_rsp, status: %d", status); 1373 } 1374 env->ReleaseByteArrayElements(address, addr, 0); 1375 1376 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 1377 } 1378 1379 static jboolean addToNowPlayingRspNative(JNIEnv* env, jobject object, 1380 jbyteArray address, jint rspStatus) { 1381 if (!sBluetoothAvrcpInterface) { 1382 ALOGE("%s: sBluetoothAvrcpInterface is null", __func__); 1383 return JNI_FALSE; 1384 } 1385 1386 jbyte* addr = env->GetByteArrayElements(address, NULL); 1387 if (!addr) { 1388 jniThrowIOException(env, EINVAL); 1389 return JNI_FALSE; 1390 } 1391 1392 RawAddress* btAddr = (RawAddress*)addr; 1393 bt_status_t status = sBluetoothAvrcpInterface->add_to_now_playing_rsp( 1394 *btAddr, (btrc_status_t)rspStatus); 1395 if (status != BT_STATUS_SUCCESS) { 1396 ALOGE("Failed add_to_now_playing_rsp, status: %d", status); 1397 } 1398 env->ReleaseByteArrayElements(address, addr, 0); 1399 1400 return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; 1401 } 1402 1403 static JNINativeMethod sMethods[] = { 1404 {"classInitNative", "()V", (void*)classInitNative}, 1405 {"initNative", "()V", (void*)initNative}, 1406 {"cleanupNative", "()V", (void*)cleanupNative}, 1407 {"getPlayStatusRspNative", "([BIII)Z", (void*)getPlayStatusRspNative}, 1408 {"getElementAttrRspNative", "([BB[I[Ljava/lang/String;)Z", 1409 (void*)getElementAttrRspNative}, 1410 {"registerNotificationRspPlayStatusNative", "(II)Z", 1411 (void*)registerNotificationRspPlayStatusNative}, 1412 {"registerNotificationRspTrackChangeNative", "(I[B)Z", 1413 (void*)registerNotificationRspTrackChangeNative}, 1414 {"registerNotificationRspPlayPosNative", "(II)Z", 1415 (void*)registerNotificationRspPlayPosNative}, 1416 {"setVolumeNative", "(I)Z", (void*)setVolumeNative}, 1417 1418 {"setAddressedPlayerRspNative", "([BI)Z", 1419 (void*)setAddressedPlayerRspNative}, 1420 1421 {"setBrowsedPlayerRspNative", "([BIBI[Ljava/lang/String;)Z", 1422 (void*)setBrowsedPlayerRspNative}, 1423 1424 {"mediaPlayerListRspNative", "([BIIBI[I[B[I[B[S[Ljava/lang/String;)Z", 1425 (void*)mediaPlayerListRspNative}, 1426 1427 {"getFolderItemsRspNative", 1428 "([BISBI[B[B[B[B[Ljava/lang/String;[I[I[Ljava/lang/String;)Z", 1429 (void*)getFolderItemsRspNative}, 1430 1431 {"changePathRspNative", "([BII)Z", (void*)changePathRspNative}, 1432 1433 {"getItemAttrRspNative", "([BIB[I[Ljava/lang/String;)Z", 1434 (void*)getItemAttrRspNative}, 1435 1436 {"playItemRspNative", "([BI)Z", (void*)playItemRspNative}, 1437 1438 {"getTotalNumOfItemsRspNative", "([BIII)Z", 1439 (void*)getTotalNumOfItemsRspNative}, 1440 1441 {"searchRspNative", "([BIII)Z", (void*)searchRspNative}, 1442 1443 {"addToNowPlayingRspNative", "([BI)Z", (void*)addToNowPlayingRspNative}, 1444 1445 {"registerNotificationRspAddrPlayerChangedNative", "(III)Z", 1446 (void*)registerNotificationRspAddrPlayerChangedNative}, 1447 1448 {"registerNotificationRspAvalPlayerChangedNative", "(I)Z", 1449 (void*)registerNotificationRspAvalPlayerChangedNative}, 1450 1451 {"registerNotificationRspUIDsChangedNative", "(II)Z", 1452 (void*)registerNotificationRspUIDsChangedNative}, 1453 1454 {"registerNotificationRspNowPlayingChangedNative", "(I)Z", 1455 (void*)registerNotificationRspNowPlayingChangedNative}}; 1456 1457 int register_com_android_bluetooth_avrcp(JNIEnv* env) { 1458 return jniRegisterNativeMethods(env, "com/android/bluetooth/avrcp/Avrcp", 1459 sMethods, NELEM(sMethods)); 1460 } 1461 1462 /* Helper function to copy attributes of item. 1463 * Assumes that all items in response have same number of attributes 1464 * 1465 * returns true on succes, false otherwise. 1466 */ 1467 static bool copy_item_attributes(JNIEnv* env, jobject object, 1468 btrc_folder_items_t* pitem, 1469 jint* p_attributesIds, 1470 jobjectArray attributesArray, int item_idx, 1471 int attribCopiedIndex) { 1472 bool success = true; 1473 1474 /* copy attributes of the item */ 1475 if (0 < pitem->media.num_attrs) { 1476 int num_attrs = pitem->media.num_attrs; 1477 ALOGI("%s num_attr = %d", __func__, num_attrs); 1478 pitem->media.p_attrs = new btrc_element_attr_val_t[num_attrs]; 1479 if (!pitem->media.p_attrs) { 1480 return false; 1481 } 1482 1483 for (int tempAtrCount = 0; tempAtrCount < pitem->media.num_attrs; 1484 ++tempAtrCount) { 1485 pitem->media.p_attrs[tempAtrCount].attr_id = 1486 p_attributesIds[attribCopiedIndex + tempAtrCount]; 1487 1488 ScopedLocalRef<jstring> text( 1489 env, (jstring)env->GetObjectArrayElement( 1490 attributesArray, attribCopiedIndex + tempAtrCount)); 1491 1492 if (!copy_jstring(pitem->media.p_attrs[tempAtrCount].text, 1493 BTRC_MAX_ATTR_STR_LEN, text.get(), env)) { 1494 success = false; 1495 ALOGE("%s: failed to copy attributes", __func__); 1496 break; 1497 } 1498 } 1499 } 1500 return success; 1501 } 1502 1503 /* Helper function to copy String data from java to native 1504 * 1505 * returns true on succes, false otherwise 1506 */ 1507 static bool copy_jstring(uint8_t* str, int maxBytes, jstring jstr, 1508 JNIEnv* env) { 1509 if (str == NULL || jstr == NULL || env == NULL) return false; 1510 1511 memset(str, 0, maxBytes); 1512 const char* p_str = env->GetStringUTFChars(jstr, NULL); 1513 size_t len = strnlen(p_str, maxBytes - 1); 1514 memcpy(str, p_str, len); 1515 1516 env->ReleaseStringUTFChars(jstr, p_str); 1517 return true; 1518 } 1519 1520 /* Helper function to cleanup items */ 1521 static void cleanup_items(btrc_folder_items_t* p_items, int numItems) { 1522 for (int item_idx = 0; item_idx < numItems; item_idx++) { 1523 /* release memory for attributes in case item is media item */ 1524 if ((BTRC_ITEM_MEDIA == p_items[item_idx].item_type) && 1525 p_items[item_idx].media.p_attrs != NULL) 1526 delete[] p_items[item_idx].media.p_attrs; 1527 } 1528 } 1529 } 1530