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

Commit 7623380d authored by Sal Savage's avatar Sal Savage
Browse files

Use getMaxConnectedAudioDevices when initializing the native stack

This change uses the system configured value for maximum connected audio
devices to inform the native stack how many A2DP Sink devices we're
allowed to have connected. The plumbing was added so the value is no
longer fixed to 1. This allows us to easily configure device count and
enable multiple connected audio devices.

The code to setActiveDevice has also been updated a bit to match what we
do in A2DP Source, allowing us to track and display the active device
for debug purposes.

Tag: #refactor
Bug: 180039146
Test: atest BluetoothInstrumentationTests
Change-Id: I890b542560907b9e1eb3a41a2b853240240b7bb5
parent 07f9aae1
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -109,7 +109,8 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
  ALOGI("%s: succeeds", __func__);
}

static void initNative(JNIEnv* env, jobject object) {
static void initNative(JNIEnv* env, jobject object,
                       jint maxConnectedAudioDevices) {
  const bt_interface_t* btInf = getBluetoothInterface();
  if (btInf == NULL) {
    ALOGE("Bluetooth module is not loaded");
@@ -136,7 +137,8 @@ static void initNative(JNIEnv* env, jobject object) {
    return;
  }

  bt_status_t status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks);
  bt_status_t status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks,
                                                     maxConnectedAudioDevices);
  if (status != BT_STATUS_SUCCESS) {
    ALOGE("Failed to initialize Bluetooth A2DP Sink, status: %d", status);
    sBluetoothA2dpInterface = NULL;
@@ -243,7 +245,7 @@ static jboolean setActiveDeviceNative(JNIEnv* env, jobject object,

static JNINativeMethod sMethods[] = {
    {"classInitNative", "()V", (void*)classInitNative},
    {"initNative", "()V", (void*)initNative},
    {"initNative", "(I)V", (void*)initNative},
    {"cleanupNative", "()V", (void*)cleanupNative},
    {"connectA2dpNative", "([B)Z", (void*)connectA2dpNative},
    {"disconnectA2dpNative", "([B)Z", (void*)disconnectA2dpNative},
+43 −8
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
@@ -44,15 +43,18 @@ import java.util.concurrent.ConcurrentHashMap;
public class A2dpSinkService extends ProfileService {
    private static final String TAG = "A2dpSinkService";
    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
    static final int MAXIMUM_CONNECTED_DEVICES = 1;
    private int mMaxConnectedAudioDevices;

    private final BluetoothAdapter mAdapter;
    private AdapterService mAdapterService;
    private DatabaseManager mDatabaseManager;
    protected Map<BluetoothDevice, A2dpSinkStateMachine> mDeviceStateMap =
            new ConcurrentHashMap<>(1);

    private final Object mStreamHandlerLock = new Object();

    private final Object mActiveDeviceLock = new Object();
    private BluetoothDevice mActiveDevice = null;

    private A2dpSinkStreamHandler mA2dpSinkStreamHandler;
    private static A2dpSinkService sService;

@@ -62,13 +64,16 @@ public class A2dpSinkService extends ProfileService {

    @Override
    protected boolean start() {
        mAdapterService = Objects.requireNonNull(AdapterService.getAdapterService(),
                "AdapterService cannot be null when A2dpSinkService starts");
        mDatabaseManager = Objects.requireNonNull(AdapterService.getAdapterService().getDatabase(),
                "DatabaseManager cannot be null when A2dpSinkService starts");

        synchronized (mStreamHandlerLock) {
            mA2dpSinkStreamHandler = new A2dpSinkStreamHandler(this, this);
        }
        initNative();
        mMaxConnectedAudioDevices = mAdapterService.getMaxConnectedAudioDevices();
        initNative(mMaxConnectedAudioDevices);
        setA2dpSinkService(this);
        return true;
    }
@@ -104,8 +109,36 @@ public class A2dpSinkService extends ProfileService {
    }


    public A2dpSinkService() {
        mAdapter = BluetoothAdapter.getDefaultAdapter();
    public A2dpSinkService() {}

    /**
     * Set the device that should be allowed to actively stream
     */
    public boolean setActiveDevice(BluetoothDevice device) {
        // Translate to byte address for JNI. Use an all 0 MAC for no active device
        byte[] address = null;
        if (device != null) {
            address = Utils.getByteAddress(device);
        } else {
            address = Utils.getBytesFromAddress("00:00:00:00:00:00");
        }

        synchronized (mActiveDeviceLock) {
            if (setActiveDeviceNative(address)) {
                mActiveDevice = device;
                return true;
            }
            return false;
        }
    }

    /**
     * Get the device that is allowed to be actively streaming
     */
    public BluetoothDevice getActiveDevice() {
        synchronized (mActiveDeviceLock) {
            return mActiveDevice;
        }
    }

    /**
@@ -343,7 +376,7 @@ public class A2dpSinkService extends ProfileService {
    List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
        if (DBG) Log.d(TAG, "getDevicesMatchingConnectionStates" + Arrays.toString(states));
        List<BluetoothDevice> deviceList = new ArrayList<>();
        Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices();
        BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices();
        int connectionState;
        for (BluetoothDevice device : bondedDevices) {
            connectionState = getConnectionState(device);
@@ -425,6 +458,8 @@ public class A2dpSinkService extends ProfileService {
    @Override
    public void dump(StringBuilder sb) {
        super.dump(sb);
        ProfileService.println(sb, "Active Device = " + getActiveDevice());
        ProfileService.println(sb, "Max Connected Devices = " + mMaxConnectedAudioDevices);
        ProfileService.println(sb, "Devices Tracked = " + mDeviceStateMap.size());
        for (A2dpSinkStateMachine stateMachine : mDeviceStateMap.values()) {
            ProfileService.println(sb,
@@ -446,7 +481,7 @@ public class A2dpSinkService extends ProfileService {

    private static native void classInitNative();

    private native void initNative();
    private native void initNative(int maxConnectedAudioDevices);

    private native void cleanupNative();

+6 −6
Original line number Diff line number Diff line
@@ -249,17 +249,16 @@ class AvrcpControllerStateMachine extends StateMachine {
     */
    boolean setActive(boolean becomeActive) {
        logD("setActive(" + becomeActive + ")");
        if (becomeActive) {
            if (isActive()) {
                return true;
            }

        A2dpSinkService a2dpSinkService = A2dpSinkService.getA2dpSinkService();
        if (a2dpSinkService == null) {
            return false;
        }
        if (becomeActive) {
            if (isActive()) {
                return true;
            }

            if (a2dpSinkService.setActiveDeviceNative(mDeviceAddress)) {
            if (a2dpSinkService.setActiveDevice(mDevice)) {
                sActiveDevice = mDevice;
                BluetoothMediaBrowserService.addressedPlayerChanged(mSessionCallbacks);
                BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
@@ -268,6 +267,7 @@ class AvrcpControllerStateMachine extends StateMachine {
            return mDevice == sActiveDevice;
        } else if (isActive()) {
            sActiveDevice = null;
            a2dpSinkService.setActiveDevice(null);
            BluetoothMediaBrowserService.trackChanged(null);
            BluetoothMediaBrowserService.addressedPlayerChanged(null);
        }
+34 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ public class A2dpSinkServiceTest {
        MockitoAnnotations.initMocks(this);
        TestUtils.setAdapterService(mAdapterService);
        doReturn(mDatabaseManager).when(mAdapterService).getDatabase();
        setMaxConnectedAudioDevices(1);
        TestUtils.startService(mServiceRule, A2dpSinkService.class);
        mService = A2dpSinkService.getA2dpSinkService();
        Assert.assertNotNull(mService);
@@ -85,6 +86,13 @@ public class A2dpSinkServiceTest {
        return mAdapter.getRemoteDevice(address);
    }

    /**
     * Set the upper connected device limit
     */
    private void setMaxConnectedAudioDevices(int maxConnectedAudioDevices) {
        when(mAdapterService.getMaxConnectedAudioDevices()).thenReturn(maxConnectedAudioDevices);
    }

    /**
     * Mock the priority of a bluetooth device
     *
@@ -120,4 +128,30 @@ public class A2dpSinkServiceTest {
        mockDevicePriority(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
        Assert.assertFalse(mService.connect(device));
    }

    /**
     * Test that we can connect multiple devices
     */
    @Test
    public void testConnectMultipleDevices() {
        setMaxConnectedAudioDevices(5);

        BluetoothDevice device1 = makeBluetoothDevice("11:11:11:11:11:11");
        BluetoothDevice device2 = makeBluetoothDevice("22:22:22:22:22:22");
        BluetoothDevice device3 = makeBluetoothDevice("33:33:33:33:33:33");
        BluetoothDevice device4 = makeBluetoothDevice("44:44:44:44:44:44");
        BluetoothDevice device5 = makeBluetoothDevice("55:55:55:55:55:55");

        mockDevicePriority(device1, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
        mockDevicePriority(device2, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
        mockDevicePriority(device3, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
        mockDevicePriority(device4, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
        mockDevicePriority(device5, BluetoothProfile.CONNECTION_POLICY_ALLOWED);

        Assert.assertTrue(mService.connect(device1));
        Assert.assertTrue(mService.connect(device2));
        Assert.assertTrue(mService.connect(device3));
        Assert.assertTrue(mService.connect(device4));
        Assert.assertTrue(mService.connect(device5));
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -113,7 +113,7 @@ public class AvrcpControllerStateMachineTest {
        TestUtils.setAdapterService(mA2dpAdapterService);
        doReturn(mDatabaseManager).when(mA2dpAdapterService).getDatabase();
        TestUtils.startService(mA2dpServiceRule, A2dpSinkService.class);
        when(mA2dpSinkService.setActiveDeviceNative(any())).thenReturn(true);
        when(mA2dpSinkService.setActiveDevice(any())).thenReturn(true);

        when(mMockResources.getBoolean(R.bool.a2dp_sink_automatically_request_audio_focus))
                .thenReturn(true);