/*
|
* Copyright (C) 2016 The Android Open Source Project
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
|
#define LOG_TAG "BluetoothAvrcpControllerJni"
|
|
#define LOG_NDEBUG 0
|
|
#include "android_runtime/AndroidRuntime.h"
|
#include "com_android_bluetooth.h"
|
#include "hardware/bt_rc.h"
|
#include "utils/Log.h"
|
|
#include <string.h>
|
#include <shared_mutex>
|
|
namespace android {
|
static jmethodID method_handlePassthroughRsp;
|
static jmethodID method_onConnectionStateChanged;
|
static jmethodID method_getRcFeatures;
|
static jmethodID method_setplayerappsettingrsp;
|
static jmethodID method_handleplayerappsetting;
|
static jmethodID method_handleplayerappsettingchanged;
|
static jmethodID method_handleSetAbsVolume;
|
static jmethodID method_handleRegisterNotificationAbsVol;
|
static jmethodID method_handletrackchanged;
|
static jmethodID method_handleplaypositionchanged;
|
static jmethodID method_handleplaystatuschanged;
|
static jmethodID method_handleGetFolderItemsRsp;
|
static jmethodID method_handleGetPlayerItemsRsp;
|
static jmethodID method_handleGroupNavigationRsp;
|
static jmethodID method_createFromNativeMediaItem;
|
static jmethodID method_createFromNativeFolderItem;
|
static jmethodID method_createFromNativePlayerItem;
|
static jmethodID method_handleChangeFolderRsp;
|
static jmethodID method_handleSetBrowsedPlayerRsp;
|
static jmethodID method_handleSetAddressedPlayerRsp;
|
static jmethodID method_handleAddressedPlayerChanged;
|
static jmethodID method_handleNowPlayingContentChanged;
|
|
static jclass class_MediaBrowser_MediaItem;
|
static jclass class_AvrcpPlayer;
|
|
static const btrc_ctrl_interface_t* sBluetoothAvrcpInterface = NULL;
|
static jobject sCallbacksObj = NULL;
|
static std::shared_timed_mutex sCallbacks_mutex;
|
|
static void btavrcp_passthrough_response_callback(const RawAddress& bd_addr,
|
int id, int pressed) {
|
ALOGI("%s: id: %d, pressed: %d", __func__, id, pressed);
|
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
if (!sCallbacksObj) {
|
ALOGE("%s: sCallbacksObj is null", __func__);
|
return;
|
}
|
|
ScopedLocalRef<jbyteArray> addr(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
|
if (!addr.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
|
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
|
(jbyte*)&bd_addr.address);
|
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handlePassthroughRsp,
|
(jint)id, (jint)pressed, addr.get());
|
}
|
|
static void btavrcp_groupnavigation_response_callback(int id, int pressed) {
|
ALOGV("%s", __func__);
|
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
if (!sCallbacksObj) {
|
ALOGE("%s: sCallbacksObj is null", __func__);
|
return;
|
}
|
|
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleGroupNavigationRsp,
|
(jint)id, (jint)pressed);
|
}
|
|
static void btavrcp_connection_state_callback(bool rc_connect, bool br_connect,
|
const RawAddress& bd_addr) {
|
ALOGI("%s: conn state: rc: %d br: %d", __func__, rc_connect, br_connect);
|
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
if (!sCallbacksObj) {
|
ALOGE("%s: sCallbacksObj is null", __func__);
|
return;
|
}
|
|
ScopedLocalRef<jbyteArray> addr(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
|
if (!addr.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
|
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
|
(jbyte*)bd_addr.address);
|
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_onConnectionStateChanged,
|
(jboolean)rc_connect, (jboolean)br_connect,
|
addr.get());
|
}
|
|
static void btavrcp_get_rcfeatures_callback(const RawAddress& bd_addr,
|
int features) {
|
ALOGV("%s", __func__);
|
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
if (!sCallbacksObj) {
|
ALOGE("%s: sCallbacksObj is null", __func__);
|
return;
|
}
|
|
ScopedLocalRef<jbyteArray> addr(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
|
if (!addr.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
|
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
|
(jbyte*)&bd_addr.address);
|
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_getRcFeatures, addr.get(),
|
(jint)features);
|
}
|
|
static void btavrcp_setplayerapplicationsetting_rsp_callback(
|
const RawAddress& bd_addr, uint8_t accepted) {
|
ALOGV("%s", __func__);
|
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
if (!sCallbacksObj) {
|
ALOGE("%s: sCallbacksObj is null", __func__);
|
return;
|
}
|
|
ScopedLocalRef<jbyteArray> addr(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
|
if (!addr.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
|
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
|
(jbyte*)&bd_addr.address);
|
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_setplayerappsettingrsp,
|
addr.get(), (jint)accepted);
|
}
|
|
static void 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) {
|
ALOGI("%s", __func__);
|
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
if (!sCallbacksObj) {
|
ALOGE("%s: sCallbacksObj is null", __func__);
|
return;
|
}
|
|
ScopedLocalRef<jbyteArray> addr(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
|
if (!addr.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
|
(jbyte*)&bd_addr.address);
|
/* TODO ext attrs
|
* Flattening defined attributes: <id,num_values,values[]>
|
*/
|
jint arraylen = 0;
|
for (int i = 0; i < num_attr; i++) {
|
/*2 bytes for id and num */
|
arraylen += 2 + app_attrs[i].num_val;
|
}
|
ALOGV(" arraylen %d", arraylen);
|
|
ScopedLocalRef<jbyteArray> playerattribs(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(arraylen));
|
if (!playerattribs.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
|
for (int i = 0, k = 0; (i < num_attr) && (k < arraylen); i++) {
|
sCallbackEnv->SetByteArrayRegion(playerattribs.get(), k, 1,
|
(jbyte*)&(app_attrs[i].attr_id));
|
k++;
|
sCallbackEnv->SetByteArrayRegion(playerattribs.get(), k, 1,
|
(jbyte*)&(app_attrs[i].num_val));
|
k++;
|
sCallbackEnv->SetByteArrayRegion(playerattribs.get(), k,
|
app_attrs[i].num_val,
|
(jbyte*)(app_attrs[i].attr_val));
|
k = k + app_attrs[i].num_val;
|
}
|
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleplayerappsetting,
|
addr.get(), playerattribs.get(), (jint)arraylen);
|
}
|
|
static void btavrcp_playerapplicationsetting_changed_callback(
|
const RawAddress& bd_addr, const btrc_player_settings_t& vals) {
|
ALOGI("%s", __func__);
|
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
if (!sCallbacksObj) {
|
ALOGE("%s: sCallbacksObj is null", __func__);
|
return;
|
}
|
|
ScopedLocalRef<jbyteArray> addr(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
|
if (!addr.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
|
(jbyte*)&bd_addr.address);
|
|
int arraylen = vals.num_attr * 2;
|
ScopedLocalRef<jbyteArray> playerattribs(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(arraylen));
|
if (!playerattribs.get()) {
|
ALOGE("Fail to new jbyteArray playerattribs ");
|
return;
|
}
|
/*
|
* Flatening format: <id,val>
|
*/
|
for (int i = 0, k = 0; (i < vals.num_attr) && (k < arraylen); i++) {
|
sCallbackEnv->SetByteArrayRegion(playerattribs.get(), k, 1,
|
(jbyte*)&(vals.attr_ids[i]));
|
k++;
|
sCallbackEnv->SetByteArrayRegion(playerattribs.get(), k, 1,
|
(jbyte*)&(vals.attr_values[i]));
|
k++;
|
}
|
sCallbackEnv->CallVoidMethod(sCallbacksObj,
|
method_handleplayerappsettingchanged, addr.get(),
|
playerattribs.get(), (jint)arraylen);
|
}
|
|
static void btavrcp_set_abs_vol_cmd_callback(const RawAddress& bd_addr,
|
uint8_t abs_vol, uint8_t label) {
|
ALOGI("%s", __func__);
|
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
if (!sCallbacksObj) {
|
ALOGE("%s: sCallbacksObj is null", __func__);
|
return;
|
}
|
|
ScopedLocalRef<jbyteArray> addr(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
|
if (!addr.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
|
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
|
(jbyte*)&bd_addr.address);
|
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleSetAbsVolume,
|
addr.get(), (jbyte)abs_vol, (jbyte)label);
|
}
|
|
static void btavrcp_register_notification_absvol_callback(
|
const RawAddress& bd_addr, uint8_t label) {
|
ALOGI("%s", __func__);
|
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
if (!sCallbacksObj) {
|
ALOGE("%s: sCallbacksObj is null", __func__);
|
return;
|
}
|
|
ScopedLocalRef<jbyteArray> addr(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
|
if (!addr.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
|
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
|
(jbyte*)&bd_addr.address);
|
sCallbackEnv->CallVoidMethod(sCallbacksObj,
|
method_handleRegisterNotificationAbsVol,
|
addr.get(), (jbyte)label);
|
}
|
|
static void btavrcp_track_changed_callback(const RawAddress& bd_addr,
|
uint8_t num_attr,
|
btrc_element_attr_val_t* p_attrs) {
|
/*
|
* byteArray will be formatted like this: id,len,string
|
* Assuming text feild to be null terminated.
|
*/
|
ALOGI("%s", __func__);
|
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
if (!sCallbacksObj) {
|
ALOGE("%s: sCallbacksObj is null", __func__);
|
return;
|
}
|
|
ScopedLocalRef<jbyteArray> addr(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
|
if (!addr.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
|
ScopedLocalRef<jintArray> attribIds(sCallbackEnv.get(),
|
sCallbackEnv->NewIntArray(num_attr));
|
if (!attribIds.get()) {
|
ALOGE(" failed to set new array for attribIds");
|
return;
|
}
|
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
|
(jbyte*)&bd_addr.address);
|
|
jclass strclazz = sCallbackEnv->FindClass("java/lang/String");
|
ScopedLocalRef<jobjectArray> stringArray(
|
sCallbackEnv.get(),
|
sCallbackEnv->NewObjectArray((jint)num_attr, strclazz, 0));
|
if (!stringArray.get()) {
|
ALOGE(" failed to get String array");
|
return;
|
}
|
|
for (jint i = 0; i < num_attr; i++) {
|
ScopedLocalRef<jstring> str(
|
sCallbackEnv.get(),
|
sCallbackEnv->NewStringUTF((char*)(p_attrs[i].text)));
|
if (!str.get()) {
|
ALOGE("Unable to get str");
|
return;
|
}
|
sCallbackEnv->SetIntArrayRegion(attribIds.get(), i, 1,
|
(jint*)&(p_attrs[i].attr_id));
|
sCallbackEnv->SetObjectArrayElement(stringArray.get(), i, str.get());
|
}
|
|
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handletrackchanged,
|
addr.get(), (jbyte)(num_attr), attribIds.get(),
|
stringArray.get());
|
}
|
|
static void btavrcp_play_position_changed_callback(const RawAddress& bd_addr,
|
uint32_t song_len,
|
uint32_t song_pos) {
|
ALOGI("%s", __func__);
|
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
if (!sCallbacksObj) {
|
ALOGE("%s: sCallbacksObj is null", __func__);
|
return;
|
}
|
|
ScopedLocalRef<jbyteArray> addr(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
|
if (!addr.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
|
(jbyte*)&bd_addr.address);
|
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleplaypositionchanged,
|
addr.get(), (jint)(song_len), (jint)song_pos);
|
}
|
|
static void btavrcp_play_status_changed_callback(
|
const RawAddress& bd_addr, btrc_play_status_t play_status) {
|
ALOGI("%s", __func__);
|
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
if (!sCallbacksObj) {
|
ALOGE("%s: sCallbacksObj is null", __func__);
|
return;
|
}
|
|
ScopedLocalRef<jbyteArray> addr(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
|
if (!addr.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
|
(jbyte*)&bd_addr.address);
|
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleplaystatuschanged,
|
addr.get(), (jbyte)play_status);
|
}
|
|
static void btavrcp_get_folder_items_callback(
|
const RawAddress& bd_addr, btrc_status_t status,
|
const btrc_folder_items_t* folder_items, uint8_t count) {
|
/* Folder items are list of items that can be either BTRC_ITEM_PLAYER
|
* BTRC_ITEM_MEDIA, BTRC_ITEM_FOLDER. Here we translate them to their java
|
* counterparts by calling the java constructor for each of the items.
|
*/
|
ALOGV("%s count %d", __func__, count);
|
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
if (!sCallbacksObj) {
|
ALOGE("%s: sCallbacksObj is null", __func__);
|
return;
|
}
|
|
ScopedLocalRef<jbyteArray> addr(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
|
if (!addr.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
|
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
|
(jbyte*)&bd_addr.address);
|
|
// Inspect if the first element is a folder/item or player listing. They are
|
// always exclusive.
|
bool isPlayerListing =
|
count > 0 && (folder_items[0].item_type == BTRC_ITEM_PLAYER);
|
|
// Initialize arrays for Folder OR Player listing.
|
ScopedLocalRef<jobjectArray> itemArray(sCallbackEnv.get(), NULL);
|
if (isPlayerListing) {
|
itemArray.reset(
|
sCallbackEnv->NewObjectArray((jint)count, class_AvrcpPlayer, 0));
|
} else {
|
itemArray.reset(sCallbackEnv->NewObjectArray(
|
(jint)count, class_MediaBrowser_MediaItem, 0));
|
}
|
if (!itemArray.get()) {
|
ALOGE("%s itemArray allocation failed.", __func__);
|
return;
|
}
|
for (int i = 0; i < count; i++) {
|
const btrc_folder_items_t* item = &(folder_items[i]);
|
ALOGV("%s item type %d", __func__, item->item_type);
|
switch (item->item_type) {
|
case BTRC_ITEM_MEDIA: {
|
// Parse name
|
ScopedLocalRef<jstring> mediaName(
|
sCallbackEnv.get(),
|
sCallbackEnv->NewStringUTF((const char*)item->media.name));
|
if (!mediaName.get()) {
|
ALOGE("%s can't allocate media name string!", __func__);
|
return;
|
}
|
// Parse UID
|
long long uid = *(long long*)item->media.uid;
|
// Parse Attrs
|
ScopedLocalRef<jintArray> attrIdArray(
|
sCallbackEnv.get(),
|
sCallbackEnv->NewIntArray(item->media.num_attrs));
|
if (!attrIdArray.get()) {
|
ALOGE("%s can't allocate attr id array!", __func__);
|
return;
|
}
|
ScopedLocalRef<jobjectArray> attrValArray(
|
sCallbackEnv.get(),
|
sCallbackEnv->NewObjectArray(
|
item->media.num_attrs,
|
sCallbackEnv->FindClass("java/lang/String"), 0));
|
if (!attrValArray.get()) {
|
ALOGE("%s can't allocate attr val array!", __func__);
|
return;
|
}
|
|
for (int j = 0; j < item->media.num_attrs; j++) {
|
sCallbackEnv->SetIntArrayRegion(
|
attrIdArray.get(), j, 1,
|
(jint*)&(item->media.p_attrs[j].attr_id));
|
ScopedLocalRef<jstring> attrValStr(
|
sCallbackEnv.get(),
|
sCallbackEnv->NewStringUTF((char*)(item->media.p_attrs[j].text)));
|
sCallbackEnv->SetObjectArrayElement(attrValArray.get(), j,
|
attrValStr.get());
|
}
|
|
ScopedLocalRef<jobject> mediaObj(
|
sCallbackEnv.get(),
|
(jobject)sCallbackEnv->CallObjectMethod(
|
sCallbacksObj, method_createFromNativeMediaItem, uid,
|
(jint)item->media.type, mediaName.get(), attrIdArray.get(),
|
attrValArray.get()));
|
if (!mediaObj.get()) {
|
ALOGE("%s failed to creae MediaItem for type ITEM_MEDIA", __func__);
|
return;
|
}
|
sCallbackEnv->SetObjectArrayElement(itemArray.get(), i, mediaObj.get());
|
break;
|
}
|
|
case BTRC_ITEM_FOLDER: {
|
// Parse name
|
ScopedLocalRef<jstring> folderName(
|
sCallbackEnv.get(),
|
sCallbackEnv->NewStringUTF((const char*)item->folder.name));
|
if (!folderName.get()) {
|
ALOGE("%s can't allocate folder name string!", __func__);
|
return;
|
}
|
// Parse UID
|
long long uid = *(long long*)item->folder.uid;
|
ScopedLocalRef<jobject> folderObj(
|
sCallbackEnv.get(),
|
(jobject)sCallbackEnv->CallObjectMethod(
|
sCallbacksObj, method_createFromNativeFolderItem, uid,
|
(jint)item->folder.type, folderName.get(),
|
(jint)item->folder.playable));
|
if (!folderObj.get()) {
|
ALOGE("%s failed to create MediaItem for type ITEM_FOLDER", __func__);
|
return;
|
}
|
sCallbackEnv->SetObjectArrayElement(itemArray.get(), i,
|
folderObj.get());
|
break;
|
}
|
|
case BTRC_ITEM_PLAYER: {
|
// Parse name
|
isPlayerListing = true;
|
jint id = (jint)item->player.player_id;
|
jint playerType = (jint)item->player.major_type;
|
jint playStatus = (jint)item->player.play_status;
|
ScopedLocalRef<jbyteArray> featureBitArray(
|
sCallbackEnv.get(),
|
sCallbackEnv->NewByteArray(BTRC_FEATURE_BIT_MASK_SIZE *
|
sizeof(uint8_t)));
|
if (!featureBitArray.get()) {
|
ALOGE("%s failed to allocate featureBitArray", __func__);
|
return;
|
}
|
sCallbackEnv->SetByteArrayRegion(
|
featureBitArray.get(), 0,
|
sizeof(uint8_t) * BTRC_FEATURE_BIT_MASK_SIZE,
|
(jbyte*)item->player.features);
|
ScopedLocalRef<jstring> playerName(
|
sCallbackEnv.get(),
|
sCallbackEnv->NewStringUTF((const char*)item->player.name));
|
if (!playerName.get()) {
|
ALOGE("%s can't allocate player name string!", __func__);
|
return;
|
}
|
ScopedLocalRef<jobject> playerObj(
|
sCallbackEnv.get(),
|
(jobject)sCallbackEnv->CallObjectMethod(
|
sCallbacksObj, method_createFromNativePlayerItem, id,
|
playerName.get(), featureBitArray.get(), playStatus,
|
playerType));
|
if (!playerObj.get()) {
|
ALOGE("%s failed to create AvrcpPlayer from ITEM_PLAYER", __func__);
|
return;
|
}
|
sCallbackEnv->SetObjectArrayElement(itemArray.get(), i,
|
playerObj.get());
|
break;
|
}
|
|
default:
|
ALOGE("%s cannot understand type %d", __func__, item->item_type);
|
}
|
}
|
|
if (isPlayerListing) {
|
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleGetPlayerItemsRsp,
|
addr.get(), itemArray.get());
|
} else {
|
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleGetFolderItemsRsp,
|
addr.get(), status, itemArray.get());
|
}
|
}
|
|
static void btavrcp_change_path_callback(const RawAddress& bd_addr,
|
uint32_t count) {
|
ALOGI("%s count %d", __func__, count);
|
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
if (!sCallbacksObj) {
|
ALOGE("%s: sCallbacksObj is null", __func__);
|
return;
|
}
|
ScopedLocalRef<jbyteArray> addr(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
|
if (!addr.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
|
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
|
(jbyte*)&bd_addr.address);
|
|
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleChangeFolderRsp,
|
addr.get(), (jint)count);
|
}
|
|
static void btavrcp_set_browsed_player_callback(const RawAddress& bd_addr,
|
uint8_t num_items,
|
uint8_t depth) {
|
ALOGI("%s items %d depth %d", __func__, num_items, depth);
|
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
if (!sCallbacksObj) {
|
ALOGE("%s: sCallbacksObj is null", __func__);
|
return;
|
}
|
ScopedLocalRef<jbyteArray> addr(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
|
if (!addr.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
|
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
|
(jbyte*)&bd_addr.address);
|
|
sCallbackEnv->CallVoidMethod(sCallbacksObj, method_handleSetBrowsedPlayerRsp,
|
addr.get(), (jint)num_items, (jint)depth);
|
}
|
|
static void btavrcp_set_addressed_player_callback(const RawAddress& bd_addr,
|
uint8_t status) {
|
ALOGI("%s status %d", __func__, status);
|
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
if (!sCallbacksObj) {
|
ALOGE("%s: sCallbacksObj is null", __func__);
|
return;
|
}
|
ScopedLocalRef<jbyteArray> addr(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
|
if (!addr.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
|
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
|
(jbyte*)&bd_addr.address);
|
|
sCallbackEnv->CallVoidMethod(sCallbacksObj,
|
method_handleSetAddressedPlayerRsp, addr.get(),
|
(jint)status);
|
}
|
|
static void btavrcp_addressed_player_changed_callback(const RawAddress& bd_addr,
|
uint16_t id) {
|
ALOGI("%s status %d", __func__, id);
|
std::shared_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
if (!sCallbacksObj) {
|
ALOGE("%s: sCallbacksObj is null", __func__);
|
return;
|
}
|
ScopedLocalRef<jbyteArray> addr(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
|
if (!addr.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
|
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
|
(jbyte*)&bd_addr.address);
|
|
sCallbackEnv->CallVoidMethod(
|
sCallbacksObj, method_handleAddressedPlayerChanged, addr.get(), (jint)id);
|
}
|
|
static void btavrcp_now_playing_content_changed_callback(
|
const RawAddress& bd_addr) {
|
ALOGI("%s", __func__);
|
|
CallbackEnv sCallbackEnv(__func__);
|
if (!sCallbackEnv.valid()) return;
|
ScopedLocalRef<jbyteArray> addr(
|
sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
|
if (!addr.get()) {
|
ALOGE("%s: Failed to allocate a new byte array", __func__);
|
return;
|
}
|
|
sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
|
(jbyte*)&bd_addr.address);
|
|
sCallbackEnv->CallVoidMethod(
|
sCallbacksObj, method_handleNowPlayingContentChanged, addr.get());
|
}
|
|
static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = {
|
sizeof(sBluetoothAvrcpCallbacks),
|
btavrcp_passthrough_response_callback,
|
btavrcp_groupnavigation_response_callback,
|
btavrcp_connection_state_callback,
|
btavrcp_get_rcfeatures_callback,
|
btavrcp_setplayerapplicationsetting_rsp_callback,
|
btavrcp_playerapplicationsetting_callback,
|
btavrcp_playerapplicationsetting_changed_callback,
|
btavrcp_set_abs_vol_cmd_callback,
|
btavrcp_register_notification_absvol_callback,
|
btavrcp_track_changed_callback,
|
btavrcp_play_position_changed_callback,
|
btavrcp_play_status_changed_callback,
|
btavrcp_get_folder_items_callback,
|
btavrcp_change_path_callback,
|
btavrcp_set_browsed_player_callback,
|
btavrcp_set_addressed_player_callback,
|
btavrcp_addressed_player_changed_callback,
|
btavrcp_now_playing_content_changed_callback};
|
|
static void classInitNative(JNIEnv* env, jclass clazz) {
|
method_handlePassthroughRsp =
|
env->GetMethodID(clazz, "handlePassthroughRsp", "(II[B)V");
|
|
method_handleGroupNavigationRsp =
|
env->GetMethodID(clazz, "handleGroupNavigationRsp", "(II)V");
|
|
method_onConnectionStateChanged =
|
env->GetMethodID(clazz, "onConnectionStateChanged", "(ZZ[B)V");
|
|
method_getRcFeatures = env->GetMethodID(clazz, "getRcFeatures", "([BI)V");
|
|
method_setplayerappsettingrsp =
|
env->GetMethodID(clazz, "setPlayerAppSettingRsp", "([BB)V");
|
|
method_handleplayerappsetting =
|
env->GetMethodID(clazz, "handlePlayerAppSetting", "([B[BI)V");
|
|
method_handleplayerappsettingchanged =
|
env->GetMethodID(clazz, "onPlayerAppSettingChanged", "([B[BI)V");
|
|
method_handleSetAbsVolume =
|
env->GetMethodID(clazz, "handleSetAbsVolume", "([BBB)V");
|
|
method_handleRegisterNotificationAbsVol =
|
env->GetMethodID(clazz, "handleRegisterNotificationAbsVol", "([BB)V");
|
|
method_handletrackchanged =
|
env->GetMethodID(clazz, "onTrackChanged", "([BB[I[Ljava/lang/String;)V");
|
|
method_handleplaypositionchanged =
|
env->GetMethodID(clazz, "onPlayPositionChanged", "([BII)V");
|
|
method_handleplaystatuschanged =
|
env->GetMethodID(clazz, "onPlayStatusChanged", "([BB)V");
|
|
method_handleGetFolderItemsRsp =
|
env->GetMethodID(clazz, "handleGetFolderItemsRsp",
|
"([BI[Landroid/media/browse/MediaBrowser$MediaItem;)V");
|
method_handleGetPlayerItemsRsp = env->GetMethodID(
|
clazz, "handleGetPlayerItemsRsp",
|
"([B[Lcom/android/bluetooth/avrcpcontroller/AvrcpPlayer;)V");
|
|
method_createFromNativeMediaItem =
|
env->GetMethodID(clazz, "createFromNativeMediaItem",
|
"(JILjava/lang/String;[I[Ljava/lang/String;)Landroid/"
|
"media/browse/MediaBrowser$MediaItem;");
|
method_createFromNativeFolderItem = env->GetMethodID(
|
clazz, "createFromNativeFolderItem",
|
"(JILjava/lang/String;I)Landroid/media/browse/MediaBrowser$MediaItem;");
|
method_createFromNativePlayerItem =
|
env->GetMethodID(clazz, "createFromNativePlayerItem",
|
"(ILjava/lang/String;[BII)Lcom/android/bluetooth/"
|
"avrcpcontroller/AvrcpPlayer;");
|
method_handleChangeFolderRsp =
|
env->GetMethodID(clazz, "handleChangeFolderRsp", "([BI)V");
|
method_handleSetBrowsedPlayerRsp =
|
env->GetMethodID(clazz, "handleSetBrowsedPlayerRsp", "([BII)V");
|
method_handleSetAddressedPlayerRsp =
|
env->GetMethodID(clazz, "handleSetAddressedPlayerRsp", "([BI)V");
|
method_handleAddressedPlayerChanged =
|
env->GetMethodID(clazz, "handleAddressedPlayerChanged", "([BI)V");
|
method_handleNowPlayingContentChanged =
|
env->GetMethodID(clazz, "handleNowPlayingContentChanged", "([B)V");
|
|
ALOGI("%s: succeeds", __func__);
|
}
|
|
static void initNative(JNIEnv* env, jobject object) {
|
std::unique_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
|
jclass tmpMediaItem =
|
env->FindClass("android/media/browse/MediaBrowser$MediaItem");
|
class_MediaBrowser_MediaItem = (jclass)env->NewGlobalRef(tmpMediaItem);
|
|
jclass tmpBtPlayer =
|
env->FindClass("com/android/bluetooth/avrcpcontroller/AvrcpPlayer");
|
class_AvrcpPlayer = (jclass)env->NewGlobalRef(tmpBtPlayer);
|
|
const bt_interface_t* btInf = getBluetoothInterface();
|
if (btInf == NULL) {
|
ALOGE("Bluetooth module is not loaded");
|
return;
|
}
|
|
if (sBluetoothAvrcpInterface != NULL) {
|
ALOGW("Cleaning up Avrcp Interface before initializing...");
|
sBluetoothAvrcpInterface->cleanup();
|
sBluetoothAvrcpInterface = NULL;
|
}
|
|
if (sCallbacksObj != NULL) {
|
ALOGW("Cleaning up Avrcp callback object");
|
env->DeleteGlobalRef(sCallbacksObj);
|
sCallbacksObj = NULL;
|
}
|
|
sBluetoothAvrcpInterface =
|
(btrc_ctrl_interface_t*)btInf->get_profile_interface(
|
BT_PROFILE_AV_RC_CTRL_ID);
|
if (sBluetoothAvrcpInterface == NULL) {
|
ALOGE("Failed to get Bluetooth Avrcp Controller Interface");
|
return;
|
}
|
|
bt_status_t status =
|
sBluetoothAvrcpInterface->init(&sBluetoothAvrcpCallbacks);
|
if (status != BT_STATUS_SUCCESS) {
|
ALOGE("Failed to initialize Bluetooth Avrcp Controller, status: %d",
|
status);
|
sBluetoothAvrcpInterface = NULL;
|
return;
|
}
|
|
sCallbacksObj = env->NewGlobalRef(object);
|
}
|
|
static void cleanupNative(JNIEnv* env, jobject object) {
|
std::unique_lock<std::shared_timed_mutex> lock(sCallbacks_mutex);
|
|
const bt_interface_t* btInf = getBluetoothInterface();
|
if (btInf == NULL) {
|
ALOGE("Bluetooth module is not loaded");
|
return;
|
}
|
|
if (sBluetoothAvrcpInterface != NULL) {
|
sBluetoothAvrcpInterface->cleanup();
|
sBluetoothAvrcpInterface = NULL;
|
}
|
|
if (sCallbacksObj != NULL) {
|
env->DeleteGlobalRef(sCallbacksObj);
|
sCallbacksObj = NULL;
|
}
|
}
|
|
static jboolean sendPassThroughCommandNative(JNIEnv* env, jobject object,
|
jbyteArray address, jint key_code,
|
jint key_state) {
|
if (!sBluetoothAvrcpInterface) return JNI_FALSE;
|
|
ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
|
|
ALOGI("key_code: %d, key_state: %d", key_code, key_state);
|
|
jbyte* addr = env->GetByteArrayElements(address, NULL);
|
if (!addr) {
|
jniThrowIOException(env, EINVAL);
|
return JNI_FALSE;
|
}
|
|
RawAddress rawAddress;
|
rawAddress.FromOctets((uint8_t*)addr);
|
bt_status_t status = sBluetoothAvrcpInterface->send_pass_through_cmd(
|
rawAddress, (uint8_t)key_code, (uint8_t)key_state);
|
if (status != BT_STATUS_SUCCESS) {
|
ALOGE("Failed sending passthru command, status: %d", status);
|
}
|
env->ReleaseByteArrayElements(address, addr, 0);
|
|
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
|
}
|
|
static jboolean sendGroupNavigationCommandNative(JNIEnv* env, jobject object,
|
jbyteArray address,
|
jint key_code,
|
jint key_state) {
|
if (!sBluetoothAvrcpInterface) return JNI_FALSE;
|
|
ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
|
|
ALOGI("key_code: %d, key_state: %d", key_code, key_state);
|
|
jbyte* addr = env->GetByteArrayElements(address, NULL);
|
if (!addr) {
|
jniThrowIOException(env, EINVAL);
|
return JNI_FALSE;
|
}
|
RawAddress rawAddress;
|
rawAddress.FromOctets((uint8_t*)addr);
|
|
bt_status_t status = sBluetoothAvrcpInterface->send_group_navigation_cmd(
|
rawAddress, (uint8_t)key_code, (uint8_t)key_state);
|
if (status != BT_STATUS_SUCCESS) {
|
ALOGE("Failed sending Grp Navigation command, status: %d", status);
|
}
|
env->ReleaseByteArrayElements(address, addr, 0);
|
|
return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
|
}
|
|
static void setPlayerApplicationSettingValuesNative(JNIEnv* env, jobject object,
|
jbyteArray address,
|
jbyte num_attrib,
|
jbyteArray attrib_ids,
|
jbyteArray attrib_val) {
|
ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
|
if (!sBluetoothAvrcpInterface) return;
|
|
jbyte* addr = env->GetByteArrayElements(address, NULL);
|
if (!addr) {
|
jniThrowIOException(env, EINVAL);
|
return;
|
}
|
|
uint8_t* pAttrs = new uint8_t[num_attrib];
|
uint8_t* pAttrsVal = new uint8_t[num_attrib];
|
if ((!pAttrs) || (!pAttrsVal)) {
|
delete[] pAttrs;
|
ALOGE("setPlayerApplicationSettingValuesNative: not have enough memeory");
|
return;
|
}
|
|
jbyte* attr = env->GetByteArrayElements(attrib_ids, NULL);
|
jbyte* attr_val = env->GetByteArrayElements(attrib_val, NULL);
|
if ((!attr) || (!attr_val)) {
|
delete[] pAttrs;
|
delete[] pAttrsVal;
|
jniThrowIOException(env, EINVAL);
|
return;
|
}
|
|
int i;
|
for (i = 0; i < num_attrib; ++i) {
|
pAttrs[i] = (uint8_t)attr[i];
|
pAttrsVal[i] = (uint8_t)attr_val[i];
|
}
|
RawAddress rawAddress;
|
rawAddress.FromOctets((uint8_t*)addr);
|
|
bt_status_t status = sBluetoothAvrcpInterface->set_player_app_setting_cmd(
|
rawAddress, (uint8_t)num_attrib, pAttrs, pAttrsVal);
|
if (status != BT_STATUS_SUCCESS) {
|
ALOGE("Failed sending setPlAppSettValNative command, status: %d", status);
|
}
|
delete[] pAttrs;
|
delete[] pAttrsVal;
|
env->ReleaseByteArrayElements(attrib_ids, attr, 0);
|
env->ReleaseByteArrayElements(attrib_val, attr_val, 0);
|
env->ReleaseByteArrayElements(address, addr, 0);
|
}
|
|
static void sendAbsVolRspNative(JNIEnv* env, jobject object, jbyteArray address,
|
jint abs_vol, jint label) {
|
if (!sBluetoothAvrcpInterface) return;
|
|
jbyte* addr = env->GetByteArrayElements(address, NULL);
|
if (!addr) {
|
jniThrowIOException(env, EINVAL);
|
return;
|
}
|
|
ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
|
RawAddress rawAddress;
|
rawAddress.FromOctets((uint8_t*)addr);
|
|
bt_status_t status = sBluetoothAvrcpInterface->set_volume_rsp(
|
rawAddress, (uint8_t)abs_vol, (uint8_t)label);
|
if (status != BT_STATUS_SUCCESS) {
|
ALOGE("Failed sending sendAbsVolRspNative command, status: %d", status);
|
}
|
env->ReleaseByteArrayElements(address, addr, 0);
|
}
|
|
static void sendRegisterAbsVolRspNative(JNIEnv* env, jobject object,
|
jbyteArray address, jbyte rsp_type,
|
jint abs_vol, jint label) {
|
if (!sBluetoothAvrcpInterface) return;
|
|
jbyte* addr = env->GetByteArrayElements(address, NULL);
|
if (!addr) {
|
jniThrowIOException(env, EINVAL);
|
return;
|
}
|
ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
|
RawAddress rawAddress;
|
rawAddress.FromOctets((uint8_t*)addr);
|
|
bt_status_t status = sBluetoothAvrcpInterface->register_abs_vol_rsp(
|
rawAddress, (btrc_notification_type_t)rsp_type, (uint8_t)abs_vol,
|
(uint8_t)label);
|
if (status != BT_STATUS_SUCCESS) {
|
ALOGE("Failed sending sendRegisterAbsVolRspNative command, status: %d",
|
status);
|
}
|
env->ReleaseByteArrayElements(address, addr, 0);
|
}
|
|
static void getPlaybackStateNative(JNIEnv* env, jobject object,
|
jbyteArray address) {
|
if (!sBluetoothAvrcpInterface) return;
|
|
jbyte* addr = env->GetByteArrayElements(address, NULL);
|
if (!addr) {
|
jniThrowIOException(env, EINVAL);
|
return;
|
}
|
ALOGV("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
|
RawAddress rawAddress;
|
rawAddress.FromOctets((uint8_t*)addr);
|
|
bt_status_t status =
|
sBluetoothAvrcpInterface->get_playback_state_cmd(rawAddress);
|
if (status != BT_STATUS_SUCCESS) {
|
ALOGE("Failed sending getPlaybackStateNative command, status: %d", status);
|
}
|
env->ReleaseByteArrayElements(address, addr, 0);
|
}
|
|
static void getNowPlayingListNative(JNIEnv* env, jobject object,
|
jbyteArray address, jint start, jint end) {
|
if (!sBluetoothAvrcpInterface) return;
|
jbyte* addr = env->GetByteArrayElements(address, NULL);
|
if (!addr) {
|
jniThrowIOException(env, EINVAL);
|
return;
|
}
|
ALOGV("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
|
RawAddress rawAddress;
|
rawAddress.FromOctets((uint8_t*)addr);
|
|
bt_status_t status = sBluetoothAvrcpInterface->get_now_playing_list_cmd(
|
rawAddress, start, end);
|
if (status != BT_STATUS_SUCCESS) {
|
ALOGE("Failed sending getNowPlayingListNative command, status: %d", status);
|
}
|
env->ReleaseByteArrayElements(address, addr, 0);
|
}
|
|
static void getFolderListNative(JNIEnv* env, jobject object, jbyteArray address,
|
jint start, jint end) {
|
if (!sBluetoothAvrcpInterface) return;
|
jbyte* addr = env->GetByteArrayElements(address, NULL);
|
if (!addr) {
|
jniThrowIOException(env, EINVAL);
|
return;
|
}
|
ALOGV("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
|
RawAddress rawAddress;
|
rawAddress.FromOctets((uint8_t*)addr);
|
|
bt_status_t status =
|
sBluetoothAvrcpInterface->get_folder_list_cmd(rawAddress, start, end);
|
if (status != BT_STATUS_SUCCESS) {
|
ALOGE("Failed sending getFolderListNative command, status: %d", status);
|
}
|
env->ReleaseByteArrayElements(address, addr, 0);
|
}
|
|
static void getPlayerListNative(JNIEnv* env, jobject object, jbyteArray address,
|
jint start, jint end) {
|
if (!sBluetoothAvrcpInterface) return;
|
jbyte* addr = env->GetByteArrayElements(address, NULL);
|
if (!addr) {
|
jniThrowIOException(env, EINVAL);
|
return;
|
}
|
ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
|
RawAddress rawAddress;
|
rawAddress.FromOctets((uint8_t*)addr);
|
|
bt_status_t status =
|
sBluetoothAvrcpInterface->get_player_list_cmd(rawAddress, start, end);
|
if (status != BT_STATUS_SUCCESS) {
|
ALOGE("Failed sending getPlayerListNative command, status: %d", status);
|
}
|
env->ReleaseByteArrayElements(address, addr, 0);
|
}
|
|
static void changeFolderPathNative(JNIEnv* env, jobject object,
|
jbyteArray address, jbyte direction,
|
jlong uid) {
|
if (!sBluetoothAvrcpInterface) return;
|
jbyte* addr = env->GetByteArrayElements(address, NULL);
|
if (!addr) {
|
jniThrowIOException(env, EINVAL);
|
return;
|
}
|
|
// jbyte* uid = env->GetByteArrayElements(uidarr, NULL);
|
// if (!uid) {
|
// jniThrowIOException(env, EINVAL);
|
// return;
|
//}
|
|
ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
|
RawAddress rawAddress;
|
rawAddress.FromOctets((uint8_t*)addr);
|
|
bt_status_t status = sBluetoothAvrcpInterface->change_folder_path_cmd(
|
rawAddress, (uint8_t)direction, (uint8_t*)&uid);
|
if (status != BT_STATUS_SUCCESS) {
|
ALOGE("Failed sending changeFolderPathNative command, status: %d", status);
|
}
|
// env->ReleaseByteArrayElements(address, addr, 0);
|
}
|
|
static void setBrowsedPlayerNative(JNIEnv* env, jobject object,
|
jbyteArray address, jint id) {
|
if (!sBluetoothAvrcpInterface) return;
|
jbyte* addr = env->GetByteArrayElements(address, NULL);
|
if (!addr) {
|
jniThrowIOException(env, EINVAL);
|
return;
|
}
|
RawAddress rawAddress;
|
rawAddress.FromOctets((uint8_t*)addr);
|
|
ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
|
bt_status_t status = sBluetoothAvrcpInterface->set_browsed_player_cmd(
|
rawAddress, (uint16_t)id);
|
if (status != BT_STATUS_SUCCESS) {
|
ALOGE("Failed sending setBrowsedPlayerNative command, status: %d", status);
|
}
|
env->ReleaseByteArrayElements(address, addr, 0);
|
}
|
|
static void setAddressedPlayerNative(JNIEnv* env, jobject object,
|
jbyteArray address, jint id) {
|
if (!sBluetoothAvrcpInterface) return;
|
jbyte* addr = env->GetByteArrayElements(address, NULL);
|
if (!addr) {
|
jniThrowIOException(env, EINVAL);
|
return;
|
}
|
RawAddress rawAddress;
|
rawAddress.FromOctets((uint8_t*)addr);
|
|
ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
|
bt_status_t status = sBluetoothAvrcpInterface->set_addressed_player_cmd(
|
rawAddress, (uint16_t)id);
|
if (status != BT_STATUS_SUCCESS) {
|
ALOGE("Failed sending setAddressedPlayerNative command, status: %d",
|
status);
|
}
|
env->ReleaseByteArrayElements(address, addr, 0);
|
}
|
|
static void playItemNative(JNIEnv* env, jobject object, jbyteArray address,
|
jbyte scope, jlong uid, jint uidCounter) {
|
if (!sBluetoothAvrcpInterface) return;
|
jbyte* addr = env->GetByteArrayElements(address, NULL);
|
if (!addr) {
|
jniThrowIOException(env, EINVAL);
|
return;
|
}
|
|
// jbyte* uid = env->GetByteArrayElements(uidArr, NULL);
|
// if (!uid) {
|
// jniThrowIOException(env, EINVAL);
|
// return;
|
// }
|
RawAddress rawAddress;
|
rawAddress.FromOctets((uint8_t*)addr);
|
|
ALOGI("%s: sBluetoothAvrcpInterface: %p", __func__, sBluetoothAvrcpInterface);
|
bt_status_t status = sBluetoothAvrcpInterface->play_item_cmd(
|
rawAddress, (uint8_t)scope, (uint8_t*)&uid, (uint16_t)uidCounter);
|
if (status != BT_STATUS_SUCCESS) {
|
ALOGE("Failed sending playItemNative command, status: %d", status);
|
}
|
env->ReleaseByteArrayElements(address, addr, 0);
|
}
|
|
static JNINativeMethod sMethods[] = {
|
{"classInitNative", "()V", (void*)classInitNative},
|
{"initNative", "()V", (void*)initNative},
|
{"cleanupNative", "()V", (void*)cleanupNative},
|
{"sendPassThroughCommandNative", "([BII)Z",
|
(void*)sendPassThroughCommandNative},
|
{"sendGroupNavigationCommandNative", "([BII)Z",
|
(void*)sendGroupNavigationCommandNative},
|
{"setPlayerApplicationSettingValuesNative", "([BB[B[B)V",
|
(void*)setPlayerApplicationSettingValuesNative},
|
{"sendAbsVolRspNative", "([BII)V", (void*)sendAbsVolRspNative},
|
{"sendRegisterAbsVolRspNative", "([BBII)V",
|
(void*)sendRegisterAbsVolRspNative},
|
{"getPlaybackStateNative", "([B)V", (void*)getPlaybackStateNative},
|
{"getNowPlayingListNative", "([BII)V", (void*)getNowPlayingListNative},
|
{"getFolderListNative", "([BII)V", (void*)getFolderListNative},
|
{"getPlayerListNative", "([BII)V", (void*)getPlayerListNative},
|
{"changeFolderPathNative", "([BBJ)V", (void*)changeFolderPathNative},
|
{"playItemNative", "([BBJI)V", (void*)playItemNative},
|
{"setBrowsedPlayerNative", "([BI)V", (void*)setBrowsedPlayerNative},
|
{"setAddressedPlayerNative", "([BI)V", (void*)setAddressedPlayerNative},
|
};
|
|
int register_com_android_bluetooth_avrcp_controller(JNIEnv* env) {
|
return jniRegisterNativeMethods(
|
env, "com/android/bluetooth/avrcpcontroller/AvrcpControllerService",
|
sMethods, NELEM(sMethods));
|
}
|
}
|