Loading android/app/src/com/android/bluetooth/le_audio/LeAudioService.java +17 −4 Original line number Diff line number Diff line Loading @@ -2108,7 +2108,8 @@ public class LeAudioService extends ProfileService { + (", isSink: " + isSink) + (" isSource: " + isSource) + (", mActiveAudioInDevice: " + mActiveAudioInDevice) + (", mActiveAudioOutDevice: " + mActiveAudioOutDevice)); + (", mActiveAudioOutDevice: " + mActiveAudioOutDevice) + (", mExposedActiveDevice: " + mExposedActiveDevice)); if (!device.equals(mExposedActiveDevice)) { return; Loading @@ -2123,9 +2124,21 @@ public class LeAudioService extends ProfileService { return; } if (device.equals(mActiveAudioInDevice) || device.equals(mActiveAudioOutDevice)) { Log.i(TAG, "Audio manager disactivate LeAudio device " + mExposedActiveDevice); mExposedActiveDevice = null; setActiveDevice(null); return; } Log.i( TAG, ("LeAudio active device switch: " + mExposedActiveDevice + " -> " + (mActiveAudioInDevice != null ? mActiveAudioInDevice : mActiveAudioOutDevice))); } /* Notifications of audio device connection/disconn events. */ Loading android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java +68 −19 Original line number Diff line number Diff line Loading @@ -1643,8 +1643,6 @@ public class LeAudioServiceTest { ArgumentCaptor<BluetoothProfileConnectionInfo> connectionInfoArgumentCaptor = ArgumentCaptor.forClass(BluetoothProfileConnectionInfo.class); /* Expect 2 calles to Audio Manager - one for output as this is * Ringtone use case */ verify(mAudioManager) .handleBluetoothActiveDeviceChanged( eq(mSingleDevice), eq(null), connectionInfoArgumentCaptor.capture()); Loading @@ -1660,39 +1658,90 @@ public class LeAudioServiceTest { assertThat(mService.setActiveDevice(mSingleDevice_2)).isTrue(); verify(mNativeInterface).groupSetActive(groupId_2); // First wait for INACTIVE state will be sent from native LeAudioStackEvent inactiveGroupState = // First wait for ACTIVE state will be sent from native LeAudioStackEvent activeGroupState = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_GROUP_STATUS_CHANGED); inactiveGroupState.valueInt1 = groupId_1; inactiveGroupState.valueInt2 = LeAudioStackEvent.GROUP_STATUS_INACTIVE; mService.messageFromNative(inactiveGroupState); activeGroupState.valueInt1 = groupId_2; activeGroupState.valueInt2 = LeAudioStackEvent.GROUP_STATUS_ACTIVE; activeGroupState.valueInt3 = groupId_1; mService.messageFromNative(activeGroupState); // Make sure suppressNoisyIntent is set to true. Soon new group will be active verify(mAudioManager) .handleBluetoothActiveDeviceChanged( eq(null), eq(mSingleDevice), connectionInfoArgumentCaptor.capture()); eq(mSingleDevice_2), eq(mSingleDevice), connectionInfoArgumentCaptor.capture()); connInfo = connectionInfoArgumentCaptor.getValue(); assertThat(connInfo.isSuppressNoisyIntent()).isTrue(); injectAudioDeviceRemoved( mSingleDevice, AudioDeviceInfo.TYPE_BLE_HEADSET, true, false, false); injectAudioDeviceAdded( mSingleDevice_2, AudioDeviceInfo.TYPE_BLE_HEADSET, true, false, true); verify(mNativeInterface, times(0)).groupSetActive(-1); } reset(mAudioManager); /** Test switching active groups */ @Test public void testAudioFrameworkAutonomousDeviceRemoval() { int groupId_1 = 1; // First wait for ACTIVE state will be sent from native LeAudioStackEvent activeGroupState = /* AUDIO_DIRECTION_OUTPUT_BIT = 0x01 */ int direction = 1; int snkAudioLocation = 3; int srcAudioLocation = 4; int availableContexts = 5 + BluetoothLeAudio.CONTEXT_TYPE_RINGTONE; // Not connected device assertThat(mService.setActiveDevice(mSingleDevice)).isFalse(); // Define some return values needed in test doReturn(-1).when(mVolumeControlService).getAudioDeviceGroupVolume(anyInt()); doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class)); // Connect both connectTestDevice(mSingleDevice, groupId_1); // Add location support LeAudioStackEvent audioConfChangedEvent = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_AUDIO_CONF_CHANGED); audioConfChangedEvent.device = mSingleDevice; audioConfChangedEvent.valueInt1 = direction; audioConfChangedEvent.valueInt2 = groupId_1; audioConfChangedEvent.valueInt3 = snkAudioLocation; audioConfChangedEvent.valueInt4 = srcAudioLocation; audioConfChangedEvent.valueInt5 = availableContexts; mService.messageFromNative(audioConfChangedEvent); assertThat(mService.setActiveDevice(mSingleDevice)).isTrue(); verify(mNativeInterface).groupSetActive(groupId_1); // Set group and device as active LeAudioStackEvent groupStatusChangedEvent = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_GROUP_STATUS_CHANGED); activeGroupState.valueInt1 = groupId_2; activeGroupState.valueInt2 = LeAudioStackEvent.GROUP_STATUS_ACTIVE; mService.messageFromNative(activeGroupState); groupStatusChangedEvent.valueInt1 = groupId_1; groupStatusChangedEvent.valueInt2 = LeAudioStackEvent.GROUP_STATUS_ACTIVE; mService.messageFromNative(groupStatusChangedEvent); verify(mTbsService).setInbandRingtoneSupport(mSingleDevice); ArgumentCaptor<BluetoothProfileConnectionInfo> connectionInfoArgumentCaptor = ArgumentCaptor.forClass(BluetoothProfileConnectionInfo.class); verify(mAudioManager) .handleBluetoothActiveDeviceChanged( eq(mSingleDevice_2), eq(null), connectionInfoArgumentCaptor.capture()); connInfo = connectionInfoArgumentCaptor.getValue(); eq(mSingleDevice), eq(null), connectionInfoArgumentCaptor.capture()); injectAudioDeviceAdded(mSingleDevice, AudioDeviceInfo.TYPE_BLE_HEADSET, true, false, true); BluetoothProfileConnectionInfo connInfo = connectionInfoArgumentCaptor.getValue(); assertThat(connInfo.isSuppressNoisyIntent()).isTrue(); injectAudioDeviceAdded( mSingleDevice_2, AudioDeviceInfo.TYPE_BLE_HEADSET, true, false, true); // AudioManager removes audio device injectAudioDeviceRemoved( mSingleDevice, AudioDeviceInfo.TYPE_BLE_HEADSET, true, false, false); verify(mNativeInterface, times(1)).groupSetActive(-1); } /** Test setting active device group without Ringtone context */ Loading system/bta/le_audio/client.cc +5 −1 Original line number Diff line number Diff line Loading @@ -1434,8 +1434,12 @@ public: * the new group so the group change is correctly handled in OnStateMachineStatusReportCb */ active_group_id_ = group_id; SuspendedForReconfiguration(); GroupStop(previous_active_group); callbacks_->OnGroupStatus(previous_active_group, GroupStatus::INACTIVE); /* Note: On purpose we are not sending INACTIVE status up to Java, because previous active * group will be provided in ACTIVE status. This is in order to have single call to audio * framework */ } /* Reset sink listener notified status */ Loading Loading
android/app/src/com/android/bluetooth/le_audio/LeAudioService.java +17 −4 Original line number Diff line number Diff line Loading @@ -2108,7 +2108,8 @@ public class LeAudioService extends ProfileService { + (", isSink: " + isSink) + (" isSource: " + isSource) + (", mActiveAudioInDevice: " + mActiveAudioInDevice) + (", mActiveAudioOutDevice: " + mActiveAudioOutDevice)); + (", mActiveAudioOutDevice: " + mActiveAudioOutDevice) + (", mExposedActiveDevice: " + mExposedActiveDevice)); if (!device.equals(mExposedActiveDevice)) { return; Loading @@ -2123,9 +2124,21 @@ public class LeAudioService extends ProfileService { return; } if (device.equals(mActiveAudioInDevice) || device.equals(mActiveAudioOutDevice)) { Log.i(TAG, "Audio manager disactivate LeAudio device " + mExposedActiveDevice); mExposedActiveDevice = null; setActiveDevice(null); return; } Log.i( TAG, ("LeAudio active device switch: " + mExposedActiveDevice + " -> " + (mActiveAudioInDevice != null ? mActiveAudioInDevice : mActiveAudioOutDevice))); } /* Notifications of audio device connection/disconn events. */ Loading
android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java +68 −19 Original line number Diff line number Diff line Loading @@ -1643,8 +1643,6 @@ public class LeAudioServiceTest { ArgumentCaptor<BluetoothProfileConnectionInfo> connectionInfoArgumentCaptor = ArgumentCaptor.forClass(BluetoothProfileConnectionInfo.class); /* Expect 2 calles to Audio Manager - one for output as this is * Ringtone use case */ verify(mAudioManager) .handleBluetoothActiveDeviceChanged( eq(mSingleDevice), eq(null), connectionInfoArgumentCaptor.capture()); Loading @@ -1660,39 +1658,90 @@ public class LeAudioServiceTest { assertThat(mService.setActiveDevice(mSingleDevice_2)).isTrue(); verify(mNativeInterface).groupSetActive(groupId_2); // First wait for INACTIVE state will be sent from native LeAudioStackEvent inactiveGroupState = // First wait for ACTIVE state will be sent from native LeAudioStackEvent activeGroupState = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_GROUP_STATUS_CHANGED); inactiveGroupState.valueInt1 = groupId_1; inactiveGroupState.valueInt2 = LeAudioStackEvent.GROUP_STATUS_INACTIVE; mService.messageFromNative(inactiveGroupState); activeGroupState.valueInt1 = groupId_2; activeGroupState.valueInt2 = LeAudioStackEvent.GROUP_STATUS_ACTIVE; activeGroupState.valueInt3 = groupId_1; mService.messageFromNative(activeGroupState); // Make sure suppressNoisyIntent is set to true. Soon new group will be active verify(mAudioManager) .handleBluetoothActiveDeviceChanged( eq(null), eq(mSingleDevice), connectionInfoArgumentCaptor.capture()); eq(mSingleDevice_2), eq(mSingleDevice), connectionInfoArgumentCaptor.capture()); connInfo = connectionInfoArgumentCaptor.getValue(); assertThat(connInfo.isSuppressNoisyIntent()).isTrue(); injectAudioDeviceRemoved( mSingleDevice, AudioDeviceInfo.TYPE_BLE_HEADSET, true, false, false); injectAudioDeviceAdded( mSingleDevice_2, AudioDeviceInfo.TYPE_BLE_HEADSET, true, false, true); verify(mNativeInterface, times(0)).groupSetActive(-1); } reset(mAudioManager); /** Test switching active groups */ @Test public void testAudioFrameworkAutonomousDeviceRemoval() { int groupId_1 = 1; // First wait for ACTIVE state will be sent from native LeAudioStackEvent activeGroupState = /* AUDIO_DIRECTION_OUTPUT_BIT = 0x01 */ int direction = 1; int snkAudioLocation = 3; int srcAudioLocation = 4; int availableContexts = 5 + BluetoothLeAudio.CONTEXT_TYPE_RINGTONE; // Not connected device assertThat(mService.setActiveDevice(mSingleDevice)).isFalse(); // Define some return values needed in test doReturn(-1).when(mVolumeControlService).getAudioDeviceGroupVolume(anyInt()); doReturn(true).when(mNativeInterface).connectLeAudio(any(BluetoothDevice.class)); // Connect both connectTestDevice(mSingleDevice, groupId_1); // Add location support LeAudioStackEvent audioConfChangedEvent = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_AUDIO_CONF_CHANGED); audioConfChangedEvent.device = mSingleDevice; audioConfChangedEvent.valueInt1 = direction; audioConfChangedEvent.valueInt2 = groupId_1; audioConfChangedEvent.valueInt3 = snkAudioLocation; audioConfChangedEvent.valueInt4 = srcAudioLocation; audioConfChangedEvent.valueInt5 = availableContexts; mService.messageFromNative(audioConfChangedEvent); assertThat(mService.setActiveDevice(mSingleDevice)).isTrue(); verify(mNativeInterface).groupSetActive(groupId_1); // Set group and device as active LeAudioStackEvent groupStatusChangedEvent = new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_GROUP_STATUS_CHANGED); activeGroupState.valueInt1 = groupId_2; activeGroupState.valueInt2 = LeAudioStackEvent.GROUP_STATUS_ACTIVE; mService.messageFromNative(activeGroupState); groupStatusChangedEvent.valueInt1 = groupId_1; groupStatusChangedEvent.valueInt2 = LeAudioStackEvent.GROUP_STATUS_ACTIVE; mService.messageFromNative(groupStatusChangedEvent); verify(mTbsService).setInbandRingtoneSupport(mSingleDevice); ArgumentCaptor<BluetoothProfileConnectionInfo> connectionInfoArgumentCaptor = ArgumentCaptor.forClass(BluetoothProfileConnectionInfo.class); verify(mAudioManager) .handleBluetoothActiveDeviceChanged( eq(mSingleDevice_2), eq(null), connectionInfoArgumentCaptor.capture()); connInfo = connectionInfoArgumentCaptor.getValue(); eq(mSingleDevice), eq(null), connectionInfoArgumentCaptor.capture()); injectAudioDeviceAdded(mSingleDevice, AudioDeviceInfo.TYPE_BLE_HEADSET, true, false, true); BluetoothProfileConnectionInfo connInfo = connectionInfoArgumentCaptor.getValue(); assertThat(connInfo.isSuppressNoisyIntent()).isTrue(); injectAudioDeviceAdded( mSingleDevice_2, AudioDeviceInfo.TYPE_BLE_HEADSET, true, false, true); // AudioManager removes audio device injectAudioDeviceRemoved( mSingleDevice, AudioDeviceInfo.TYPE_BLE_HEADSET, true, false, false); verify(mNativeInterface, times(1)).groupSetActive(-1); } /** Test setting active device group without Ringtone context */ Loading
system/bta/le_audio/client.cc +5 −1 Original line number Diff line number Diff line Loading @@ -1434,8 +1434,12 @@ public: * the new group so the group change is correctly handled in OnStateMachineStatusReportCb */ active_group_id_ = group_id; SuspendedForReconfiguration(); GroupStop(previous_active_group); callbacks_->OnGroupStatus(previous_active_group, GroupStatus::INACTIVE); /* Note: On purpose we are not sending INACTIVE status up to Java, because previous active * group will be provided in ACTIVE status. This is in order to have single call to audio * framework */ } /* Reset sink listener notified status */ Loading