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

Commit ba2dd408 authored by Sanket Agarwal's avatar Sanket Agarwal Committed by Gerrit Code Review
Browse files

Merge "Implement set addressed player functionality."

parents 93eadca0 7a137cf1
Loading
Loading
Loading
Loading
+36 −2
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ static jmethodID method_createFromNativeFolderItem;
static jmethodID method_createFromNativePlayerItem;
static jmethodID method_handleChangeFolderRsp;
static jmethodID method_handleSetBrowsedPlayerRsp;
static jmethodID method_handleSetAddressedPlayerRsp;

static jclass class_MediaBrowser_MediaItem;
static jclass class_AvrcpPlayer;
@@ -543,6 +544,17 @@ static void btavrcp_set_browsed_player_callback(
        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 = {
    sizeof(sBluetoothAvrcpCallbacks),
    btavrcp_passthrough_response_callback,
@@ -559,7 +571,8 @@ static btrc_ctrl_callbacks_t sBluetoothAvrcpCallbacks = {
    btavrcp_play_status_changed_callback,
    btavrcp_get_folder_items_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) {
@@ -618,6 +631,8 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
        env->GetMethodID(clazz, "handleChangeFolderRsp", "(I)V");
    method_handleSetBrowsedPlayerRsp =
        env->GetMethodID(clazz, "handleSetBrowsedPlayerRsp", "(II)V");
    method_handleSetAddressedPlayerRsp =
        env->GetMethodID(clazz, "handleSetAddressedPlayerRsp", "(I)V");
    ALOGI("%s: succeeds", __FUNCTION__);
}

@@ -931,7 +946,25 @@ static void setBrowsedPlayerNative(JNIEnv *env, jobject object, jbyteArray addre
    ALOGI("%s: sBluetoothAvrcpInterface: %p", __FUNCTION__, sBluetoothAvrcpInterface);
    if ((status = sBluetoothAvrcpInterface->set_browsed_player_cmd(
            (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);
}
@@ -980,6 +1013,7 @@ static JNINativeMethod sMethods[] = {
    {"changeFolderPathNative", "([BB[B)V", (void *) changeFolderPathNative},
    {"playItemNative", "([BB[BI)V", (void *) playItemNative},
    {"setBrowsedPlayerNative", "([BI)V", (void *) setBrowsedPlayerNative},
    {"setAddressedPlayerNative", "([BI)V", (void *) setAddressedPlayerNative},
};

int register_com_android_bluetooth_avrcp_controller(JNIEnv* env)
+10 −0
Original line number Diff line number Diff line
@@ -1046,6 +1046,15 @@ public class AvrcpControllerService extends ProfileService {
        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
    public void dump(StringBuilder sb) {
        super.dump(sb);
@@ -1110,4 +1119,5 @@ public class AvrcpControllerService extends ProfileService {
    native static void playItemNative(
        byte[] address, byte scope, byte[] uid, int uidCounter);
    native static void setBrowsedPlayerNative(byte[] address, int playerId);
    native static void setAddressedPlayerNative(byte[] address, int playerId);
}
+74 −10
Original line number 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_FOLDER_PATH = 112;
    static final int MESSAGE_PROCESS_SET_BROWSED_PLAYER = 113;
    static final int MESSAGE_PROCESS_SET_ADDRESSED_PLAYER = 114;

    // commands from A2DP sink
    static final int MESSAGE_STOP_METADATA_BROADCASTS = 201;
@@ -114,6 +115,7 @@ class AvrcpControllerStateMachine extends StateMachine {
    private final State mDisconnected;
    private final State mConnected;
    private final SetBrowsedPlayer mSetBrowsedPlayer;
    private final SetAddresedPlayerAndPlayItem mSetAddrPlayer;
    private final ChangeFolderPath mChangeFolderPath;
    private final GetFolderList mGetFolderList;
    private final GetPlayerListing mGetPlayerListing;
@@ -133,11 +135,7 @@ class AvrcpControllerStateMachine extends StateMachine {
    private boolean mBroadcastMetadata = false;
    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.
    // Only valid if mCurrentPlayer != null.
    private int mBrowseDepth = 0;

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

        // Used to change folder path and fetch the new folder listing.
        mSetBrowsedPlayer = new SetBrowsedPlayer();
        mSetAddrPlayer = new SetAddresedPlayerAndPlayItem();
        mChangeFolderPath = new ChangeFolderPath();
        mGetFolderList = new GetFolderList();
        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
        // deferred so that once we transition to the mConnected we can process them hence.
        addState(mSetBrowsedPlayer, mConnected);
        addState(mSetAddrPlayer, mConnected);
        addState(mChangeFolderPath, mConnected);
        addState(mGetFolderList, mConnected);
        addState(mGetPlayerListing, mConnected);
@@ -295,12 +295,33 @@ class AvrcpControllerStateMachine extends StateMachine {

                    case MESSAGE_FETCH_ATTR_AND_PLAY_ITEM: {
                        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)
                            // 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(
                            mRemoteDevice.getBluetoothAddress(), (byte) msg.arg1,
                            AvrcpControllerService.hexStringToByteUID(uid), (int) 0);
                                mRemoteDevice.getBluetoothAddress(), (byte) scope,
                                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;
                    }

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

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

    BrowseTree() {
    }
@@ -289,6 +291,34 @@ public class BrowseTree {
        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
    public String toString() {
        return mBrowseMap.toString();