Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7a137cf1 authored by Sanket Agarwal's avatar Sanket Agarwal
Browse files

Implement set addressed player functionality.

Bug: b/31554234

Change-Id: Ibe1170bae58e3a3d68dc942b998ca2deee3b27f8
(cherry picked from commit c6a0ec780118dc7fae298d382fba5a0421749c51)
parent 93eadca0
Loading
Loading
Loading
Loading
+36 −2
Original line number Original line Diff line number Diff line
@@ -45,6 +45,7 @@ static jmethodID method_createFromNativeFolderItem;
static jmethodID method_createFromNativePlayerItem;
static jmethodID method_createFromNativePlayerItem;
static jmethodID method_handleChangeFolderRsp;
static jmethodID method_handleChangeFolderRsp;
static jmethodID method_handleSetBrowsedPlayerRsp;
static jmethodID method_handleSetBrowsedPlayerRsp;
static jmethodID method_handleSetAddressedPlayerRsp;


static jclass class_MediaBrowser_MediaItem;
static jclass class_MediaBrowser_MediaItem;
static jclass class_AvrcpPlayer;
static jclass class_AvrcpPlayer;
@@ -543,6 +544,17 @@ static void btavrcp_set_browsed_player_callback(
        sCallbacksObj, method_handleSetBrowsedPlayerRsp, (jint) num_items, (jint) depth);
        sCallbacksObj, method_handleSetBrowsedPlayerRsp, (jint) num_items, (jint) depth);
}
}


static void btavrcp_set_addressed_player_callback(
        bt_bdaddr_t *bd_addr, uint8_t status) {
    ALOGI("%s status %d", __FUNCTION__, status);

    CallbackEnv sCallbackEnv(__func__);
    if (!sCallbackEnv.valid()) return;

    sCallbackEnv->CallVoidMethod(
        sCallbacksObj, method_handleSetAddressedPlayerRsp, (jint) status);
}

static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = {
static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = {
    sizeof(sBluetoothAvrcpCallbacks),
    sizeof(sBluetoothAvrcpCallbacks),
    btavrcp_passthrough_response_callback,
    btavrcp_passthrough_response_callback,
@@ -559,7 +571,8 @@ static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = {
    btavrcp_play_status_changed_callback,
    btavrcp_play_status_changed_callback,
    btavrcp_get_folder_items_callback,
    btavrcp_get_folder_items_callback,
    btavrcp_change_path_callback,
    btavrcp_change_path_callback,
    btavrcp_set_browsed_player_callback
    btavrcp_set_browsed_player_callback,
    btavrcp_set_addressed_player_callback
};
};


static void classInitNative(JNIEnv* env, jclass clazz) {
static void classInitNative(JNIEnv* env, jclass clazz) {
@@ -618,6 +631,8 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
        env->GetMethodID(clazz, "handleChangeFolderRsp", "(I)V");
        env->GetMethodID(clazz, "handleChangeFolderRsp", "(I)V");
    method_handleSetBrowsedPlayerRsp =
    method_handleSetBrowsedPlayerRsp =
        env->GetMethodID(clazz, "handleSetBrowsedPlayerRsp", "(II)V");
        env->GetMethodID(clazz, "handleSetBrowsedPlayerRsp", "(II)V");
    method_handleSetAddressedPlayerRsp =
        env->GetMethodID(clazz, "handleSetAddressedPlayerRsp", "(I)V");
    ALOGI("%s: succeeds", __FUNCTION__);
    ALOGI("%s: succeeds", __FUNCTION__);
}
}


@@ -931,7 +946,25 @@ static void setBrowsedPlayerNative(JNIEnv *env, jobject object, jbyteArray addre
    ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
    ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
    if ((status = sBluetoothAvrcpInterface->set_browsed_player_cmd(
    if ((status = sBluetoothAvrcpInterface->set_browsed_player_cmd(
            (bt_bdaddr_t *) addr, (uint16_t) id)) != BT_STATUS_SUCCESS) {
            (bt_bdaddr_t *) addr, (uint16_t) id)) != BT_STATUS_SUCCESS) {
        ALOGE("Failed sending changeFolderPathNative command, status: %d", status);
        ALOGE("Failed sending setBrowsedPlayerNative command, status: %d", status);
    }
    env->ReleaseByteArrayElements(address, addr, 0);
}

static void setAddressedPlayerNative(JNIEnv *env, jobject object, jbyteArray address, jint id) {
    bt_status_t status;

    if (!sBluetoothAvrcpInterface) return;
    jbyte *addr = env->GetByteArrayElements(address, NULL);
    if (!addr) {
        jniThrowIOException(env, EINVAL);
        return;
    }

    ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
    if ((status = sBluetoothAvrcpInterface->set_addressed_player_cmd(
            (bt_bdaddr_t *) addr, (uint16_t) id)) != BT_STATUS_SUCCESS) {
        ALOGE("Failed sending setAddressedPlayerNative command, status: %d", status);
    }
    }
    env->ReleaseByteArrayElements(address, addr, 0);
    env->ReleaseByteArrayElements(address, addr, 0);
}
}
@@ -980,6 +1013,7 @@ static JNINativeMethod sMethods[] = {
    {"changeFolderPathNative", "([BB[B)V", (void *) changeFolderPathNative},
    {"changeFolderPathNative", "([BB[B)V", (void *) changeFolderPathNative},
    {"playItemNative", "([BB[BI)V", (void *) playItemNative},
    {"playItemNative", "([BB[BI)V", (void *) playItemNative},
    {"setBrowsedPlayerNative", "([BI)V", (void *) setBrowsedPlayerNative},
    {"setBrowsedPlayerNative", "([BI)V", (void *) setBrowsedPlayerNative},
    {"setAddressedPlayerNative", "([BI)V", (void *) setAddressedPlayerNative},
};
};


int register_com_android_bluetooth_avrcp_controller(JNIEnv* env)
int register_com_android_bluetooth_avrcp_controller(JNIEnv* env)
+10 −0
Original line number Original line Diff line number Diff line
@@ -1046,6 +1046,15 @@ public class AvrcpControllerService extends ProfileService {
        mAvrcpCtSm.sendMessage(msg);
        mAvrcpCtSm.sendMessage(msg);
    }
    }


    private void handleSetAddressedPlayerRsp(int status) {
        if (DBG) {
            Log.d(TAG, "handleSetAddressedPlayerRsp status: " + status);
        }
        Message msg = mAvrcpCtSm.obtainMessage(
            AvrcpControllerStateMachine.MESSAGE_PROCESS_SET_ADDRESSED_PLAYER);
        mAvrcpCtSm.sendMessage(msg);
    }

    @Override
    @Override
    public void dump(StringBuilder sb) {
    public void dump(StringBuilder sb) {
        super.dump(sb);
        super.dump(sb);
@@ -1110,4 +1119,5 @@ public class AvrcpControllerService extends ProfileService {
    native static void playItemNative(
    native static void playItemNative(
        byte[] address, byte scope, byte[] uid, int uidCounter);
        byte[] address, byte scope, byte[] uid, int uidCounter);
    native static void setBrowsedPlayerNative(byte[] address, int playerId);
    native static void setBrowsedPlayerNative(byte[] address, int playerId);
    native static void setAddressedPlayerNative(byte[] address, int playerId);
}
}
+74 −10
Original line number Original line Diff line number Diff line
@@ -73,6 +73,7 @@ class AvrcpControllerStateMachine extends StateMachine {
    static final int MESSAGE_PROCESS_GET_PLAYER_ITEMS = 111;
    static final int MESSAGE_PROCESS_GET_PLAYER_ITEMS = 111;
    static final int MESSAGE_PROCESS_FOLDER_PATH = 112;
    static final int MESSAGE_PROCESS_FOLDER_PATH = 112;
    static final int MESSAGE_PROCESS_SET_BROWSED_PLAYER = 113;
    static final int MESSAGE_PROCESS_SET_BROWSED_PLAYER = 113;
    static final int MESSAGE_PROCESS_SET_ADDRESSED_PLAYER = 114;


    // commands from A2DP sink
    // commands from A2DP sink
    static final int MESSAGE_STOP_METADATA_BROADCASTS = 201;
    static final int MESSAGE_STOP_METADATA_BROADCASTS = 201;
@@ -114,6 +115,7 @@ class AvrcpControllerStateMachine extends StateMachine {
    private final State mDisconnected;
    private final State mDisconnected;
    private final State mConnected;
    private final State mConnected;
    private final SetBrowsedPlayer mSetBrowsedPlayer;
    private final SetBrowsedPlayer mSetBrowsedPlayer;
    private final SetAddresedPlayerAndPlayItem mSetAddrPlayer;
    private final ChangeFolderPath mChangeFolderPath;
    private final ChangeFolderPath mChangeFolderPath;
    private final GetFolderList mGetFolderList;
    private final GetFolderList mGetFolderList;
    private final GetPlayerListing mGetPlayerListing;
    private final GetPlayerListing mGetPlayerListing;
@@ -133,11 +135,7 @@ class AvrcpControllerStateMachine extends StateMachine {
    private boolean mBroadcastMetadata = false;
    private boolean mBroadcastMetadata = false;
    private int previousPercentageVol = -1;
    private int previousPercentageVol = -1;


    // New addressed player.
    private String mCurrentPlayer = null;

    // Depth from root of current browsing. This can be used to move to root directly.
    // Depth from root of current browsing. This can be used to move to root directly.
    // Only valid if mCurrentPlayer != null.
    private int mBrowseDepth = 0;
    private int mBrowseDepth = 0;


    // Browse tree.
    // Browse tree.
@@ -156,6 +154,7 @@ class AvrcpControllerStateMachine extends StateMachine {


        // Used to change folder path and fetch the new folder listing.
        // Used to change folder path and fetch the new folder listing.
        mSetBrowsedPlayer = new SetBrowsedPlayer();
        mSetBrowsedPlayer = new SetBrowsedPlayer();
        mSetAddrPlayer = new SetAddresedPlayerAndPlayItem();
        mChangeFolderPath = new ChangeFolderPath();
        mChangeFolderPath = new ChangeFolderPath();
        mGetFolderList = new GetFolderList();
        mGetFolderList = new GetFolderList();
        mGetPlayerListing = new GetPlayerListing();
        mGetPlayerListing = new GetPlayerListing();
@@ -169,6 +168,7 @@ class AvrcpControllerStateMachine extends StateMachine {
        // only handle the messages that are relevant to the sub-action. Everything else should be
        // only handle the messages that are relevant to the sub-action. Everything else should be
        // deferred so that once we transition to the mConnected we can process them hence.
        // deferred so that once we transition to the mConnected we can process them hence.
        addState(mSetBrowsedPlayer, mConnected);
        addState(mSetBrowsedPlayer, mConnected);
        addState(mSetAddrPlayer, mConnected);
        addState(mChangeFolderPath, mConnected);
        addState(mChangeFolderPath, mConnected);
        addState(mGetFolderList, mConnected);
        addState(mGetFolderList, mConnected);
        addState(mGetPlayerListing, mConnected);
        addState(mGetPlayerListing, mConnected);
@@ -295,12 +295,33 @@ class AvrcpControllerStateMachine extends StateMachine {


                    case MESSAGE_FETCH_ATTR_AND_PLAY_ITEM: {
                    case MESSAGE_FETCH_ATTR_AND_PLAY_ITEM: {
                        int scope = msg.arg1;
                        int scope = msg.arg1;
                        String uid = (String) msg.obj;
                        String playItemUid = (String) msg.obj;
                        BrowseTree.BrowseNode currBrPlayer =
                            mBrowseTree.getCurrentBrowsedPlayer();
                        BrowseTree.BrowseNode currAddrPlayer =
                            mBrowseTree.getCurrentAddressedPlayer();
                        if (DBG) {
                            Log.d(TAG, "currBrPlayer " + currBrPlayer +
                                " currAddrPlayer " + currAddrPlayer);
                        }

                        if (currBrPlayer == null || currBrPlayer.equals(currAddrPlayer)) {
                            // String is encoded as a Hex String (mostly for display purposes)
                            // String is encoded as a Hex String (mostly for display purposes)
                            // hence convert this back to real byte string.
                            // hence convert this back to real byte string.
                            // NOTE: It may be possible that sending play while the same item is
                            // playing leads to reset of track.
                            AvrcpControllerService.playItemNative(
                            AvrcpControllerService.playItemNative(
                            mRemoteDevice.getBluetoothAddress(), (byte) msg.arg1,
                                mRemoteDevice.getBluetoothAddress(), (byte) scope,
                            AvrcpControllerService.hexStringToByteUID(uid), (int) 0);
                                AvrcpControllerService.hexStringToByteUID(playItemUid), (int) 0);
                        } else {
                            // Send out the request for setting addressed player.
                            AvrcpControllerService.setAddressedPlayerNative(
                                mRemoteDevice.getBluetoothAddress(),
                                currBrPlayer.getPlayerID());
                            mSetAddrPlayer.setItemAndScope(
                                currBrPlayer.getID(), playItemUid, scope);
                            transitionTo(mSetAddrPlayer);
                        }
                        break;
                        break;
                    }
                    }


@@ -759,6 +780,8 @@ class AvrcpControllerStateMachine extends StateMachine {
                        transitionTo(mMoveToRoot);
                        transitionTo(mMoveToRoot);
                    }
                    }
                    mBrowseTree.setCurrentBrowsedFolder(mID);
                    mBrowseTree.setCurrentBrowsedFolder(mID);
                    // Also set the browsed player here.
                    mBrowseTree.setCurrentBrowsedPlayer(mID);
                    break;
                    break;


                case MESSAGE_INTERNAL_CMD_TIMEOUT:
                case MESSAGE_INTERNAL_CMD_TIMEOUT:
@@ -774,6 +797,47 @@ class AvrcpControllerStateMachine extends StateMachine {
        }
        }
    }
    }


    class SetAddresedPlayerAndPlayItem extends CmdState {
        private String STATE_TAG = "AVRCPSM.SetAddresedPlayerAndPlayItem";
        int mScope;
        String mPlayItemId;
        String mAddrPlayerId;

        public void setItemAndScope(String addrPlayerId, String playItemId, int scope) {
            mAddrPlayerId = addrPlayerId;
            mPlayItemId = playItemId;
            mScope = scope;
        }

        @Override
        public boolean processMessage(Message msg) {
            Log.d(STATE_TAG, "processMessage " + msg);
            switch (msg.what) {
                case MESSAGE_PROCESS_SET_ADDRESSED_PLAYER:
                    // Set the new addressed player.
                    mBrowseTree.setCurrentAddressedPlayer(mAddrPlayerId);

                    // And now play the item.
                    AvrcpControllerService.playItemNative(
                        mRemoteDevice.getBluetoothAddress(), (byte) mScope,
                        AvrcpControllerService.hexStringToByteUID(mPlayItemId), (int) 0);

                    // Transition to connected state here.
                    transitionTo(mConnected);
                    break;

                case MESSAGE_INTERNAL_CMD_TIMEOUT:
                    transitionTo(mConnected);
                    break;

                default:
                    Log.d(STATE_TAG, "deferring message " + msg + " to connected!");
                    deferMessage(msg);
            }
            return true;
        }
    }

    // Class template for commands. Each state should do the following:
    // Class template for commands. Each state should do the following:
    // (a) In enter() send a timeout message which could be tracked in the
    // (a) In enter() send a timeout message which could be tracked in the
    // processMessage() stage.
    // processMessage() stage.
+30 −0
Original line number Original line Diff line number Diff line
@@ -56,6 +56,8 @@ public class BrowseTree {
    // Static instance of Folder ID <-> Folder Instance (for navigation purposes)
    // Static instance of Folder ID <-> Folder Instance (for navigation purposes)
    private final HashMap<String, BrowseNode> mBrowseMap = new HashMap<String, BrowseNode>();
    private final HashMap<String, BrowseNode> mBrowseMap = new HashMap<String, BrowseNode>();
    private BrowseNode mCurrentBrowseNode;
    private BrowseNode mCurrentBrowseNode;
    private BrowseNode mCurrentBrowsedPlayer;
    private BrowseNode mCurrentAddressedPlayer;


    BrowseTree() {
    BrowseTree() {
    }
    }
@@ -289,6 +291,34 @@ public class BrowseTree {
        return mCurrentBrowseNode;
        return mCurrentBrowseNode;
    }
    }


    synchronized boolean setCurrentBrowsedPlayer(String uid) {
        BrowseNode bn = findFolderByIDLocked(uid);
        if (bn == null) {
            Log.e(TAG, "Setting an unknown browsed player, ignoring bn " + uid);
            return false;
        }
        mCurrentBrowsedPlayer = bn;
        return true;
    }

    synchronized BrowseNode getCurrentBrowsedPlayer() {
        return mCurrentBrowsedPlayer;
    }

    synchronized boolean setCurrentAddressedPlayer(String uid) {
        BrowseNode bn = findFolderByIDLocked(uid);
        if (bn == null) {
            Log.e(TAG, "Setting an unknown addressed player, ignoring bn " + uid);
            return false;
        }
        mCurrentAddressedPlayer = bn;
        return true;
    }

    synchronized BrowseNode getCurrentAddressedPlayer() {
        return mCurrentAddressedPlayer;
    }

    @Override
    @Override
    public String toString() {
    public String toString() {
        return mBrowseMap.toString();
        return mBrowseMap.toString();