Loading android/app/src/com/android/bluetooth/a2dp/A2dpService.java +34 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,9 @@ public class A2dpService extends ProfileService { private static final boolean DBG = true; private static final String TAG = "A2dpService"; // TODO(b/240635097): remove in U private static final int SOURCE_CODEC_TYPE_OPUS = 6; private static A2dpService sA2dpService; private AdapterService mAdapterService; Loading Loading @@ -600,6 +603,7 @@ public class A2dpService extends ProfileService { // This needs to happen before we inform the audio manager that the device // disconnected. Please see comment in updateAndBroadcastActiveDevice() for why. updateAndBroadcastActiveDevice(device); updateLowLatencyAudioSupport(device); BluetoothDevice newActiveDevice = null; synchronized (mStateMachines) { Loading Loading @@ -819,6 +823,7 @@ public class A2dpService extends ProfileService { Log.e(TAG, "enableOptionalCodecs: Codec status is null"); return; } updateLowLatencyAudioSupport(device); mA2dpCodecConfig.enableOptionalCodecs(device, codecStatus.getCodecConfig()); } Loading Loading @@ -849,6 +854,7 @@ public class A2dpService extends ProfileService { Log.e(TAG, "disableOptionalCodecs: Codec status is null"); return; } updateLowLatencyAudioSupport(device); mA2dpCodecConfig.disableOptionalCodecs(device, codecStatus.getCodecConfig()); } Loading Loading @@ -1208,6 +1214,34 @@ public class A2dpService extends ProfileService { } } /** * Check for low-latency codec support and inform AdapterService * * @param device device whose audio low latency will be allowed or disallowed */ @VisibleForTesting public void updateLowLatencyAudioSupport(BluetoothDevice device) { synchronized (mStateMachines) { A2dpStateMachine sm = mStateMachines.get(device); if (sm == null) { return; } BluetoothCodecStatus codecStatus = sm.getCodecStatus(); boolean lowLatencyAudioAllow = false; BluetoothCodecConfig lowLatencyCodec = new BluetoothCodecConfig.Builder() .setCodecType(SOURCE_CODEC_TYPE_OPUS) // remove in U .build(); if (codecStatus != null && codecStatus.isCodecConfigSelectable(lowLatencyCodec) && getOptionalCodecsEnabled(device) == BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) { lowLatencyAudioAllow = true; } mAdapterService.allowLowLatencyAudio(lowLatencyAudioAllow, device); } } private void connectionStateChanged(BluetoothDevice device, int fromState, int toState) { if ((device == null) || (fromState == toState)) { return; Loading android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java +2 −0 Original line number Diff line number Diff line Loading @@ -483,6 +483,7 @@ final class A2dpStateMachine extends StateMachine { // codecs (perhaps it's had a firmware update, etc.) and save that state if // it differs from what we had saved before. mA2dpService.updateOptionalCodecsSupport(mDevice); mA2dpService.updateLowLatencyAudioSupport(mDevice); broadcastConnectionState(mConnectionState, mLastConnectionState); // Upon connected, the audio starts out as stopped broadcastAudioState(BluetoothA2dp.STATE_NOT_PLAYING, Loading Loading @@ -655,6 +656,7 @@ final class A2dpStateMachine extends StateMachine { // for this codec change event. mA2dpService.updateOptionalCodecsSupport(mDevice); } mA2dpService.updateLowLatencyAudioSupport(mDevice); if (mA2dpOffloadEnabled) { boolean update = false; BluetoothCodecConfig newCodecConfig = mCodecStatus.getCodecConfig(); Loading android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpStateMachineTest.java +15 −0 Original line number Diff line number Diff line Loading @@ -362,6 +362,7 @@ public class A2dpStateMachineTest { // Selected codec = SBC, selectable codec = SBC mA2dpStateMachine.processCodecConfigEvent(codecStatusSbcAndSbc); verify(mA2dpService).codecConfigUpdated(mTestDevice, codecStatusSbcAndSbc, false); verify(mA2dpService, times(1)).updateLowLatencyAudioSupport(mTestDevice); // Inject an event to change state machine to connected state A2dpStackEvent connStCh = Loading @@ -379,6 +380,7 @@ public class A2dpStateMachineTest { // Verify that state machine update optional codec when enter connected state verify(mA2dpService, times(1)).updateOptionalCodecsSupport(mTestDevice); verify(mA2dpService, times(2)).updateLowLatencyAudioSupport(mTestDevice); // Change codec status when device connected. // Selected codec = SBC, selectable codec = SBC+AAC Loading @@ -387,12 +389,14 @@ public class A2dpStateMachineTest { verify(mA2dpService).codecConfigUpdated(mTestDevice, codecStatusSbcAndSbcAac, true); } verify(mA2dpService, times(2)).updateOptionalCodecsSupport(mTestDevice); verify(mA2dpService, times(3)).updateLowLatencyAudioSupport(mTestDevice); // Update selected codec with selectable codec unchanged. // Selected codec = AAC, selectable codec = SBC+AAC mA2dpStateMachine.processCodecConfigEvent(codecStatusAacAndSbcAac); verify(mA2dpService).codecConfigUpdated(mTestDevice, codecStatusAacAndSbcAac, false); verify(mA2dpService, times(2)).updateOptionalCodecsSupport(mTestDevice); verify(mA2dpService, times(4)).updateLowLatencyAudioSupport(mTestDevice); // Update selected codec // Selected codec = OPUS, selectable codec = SBC+AAC+OPUS Loading @@ -401,5 +405,16 @@ public class A2dpStateMachineTest { verify(mA2dpService).codecConfigUpdated(mTestDevice, codecStatusOpusAndSbcAacOpus, true); } verify(mA2dpService, times(3)).updateOptionalCodecsSupport(mTestDevice); // Check if low latency audio been updated. verify(mA2dpService, times(5)).updateLowLatencyAudioSupport(mTestDevice); // Update selected codec with selectable codec changed. // Selected codec = SBC, selectable codec = SBC+AAC mA2dpStateMachine.processCodecConfigEvent(codecStatusSbcAndSbcAac); if (!offloadEnabled) { verify(mA2dpService).codecConfigUpdated(mTestDevice, codecStatusSbcAndSbcAac, true); } // Check if low latency audio been update. verify(mA2dpService, times(6)).updateLowLatencyAudioSupport(mTestDevice); } } Loading
android/app/src/com/android/bluetooth/a2dp/A2dpService.java +34 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,9 @@ public class A2dpService extends ProfileService { private static final boolean DBG = true; private static final String TAG = "A2dpService"; // TODO(b/240635097): remove in U private static final int SOURCE_CODEC_TYPE_OPUS = 6; private static A2dpService sA2dpService; private AdapterService mAdapterService; Loading Loading @@ -600,6 +603,7 @@ public class A2dpService extends ProfileService { // This needs to happen before we inform the audio manager that the device // disconnected. Please see comment in updateAndBroadcastActiveDevice() for why. updateAndBroadcastActiveDevice(device); updateLowLatencyAudioSupport(device); BluetoothDevice newActiveDevice = null; synchronized (mStateMachines) { Loading Loading @@ -819,6 +823,7 @@ public class A2dpService extends ProfileService { Log.e(TAG, "enableOptionalCodecs: Codec status is null"); return; } updateLowLatencyAudioSupport(device); mA2dpCodecConfig.enableOptionalCodecs(device, codecStatus.getCodecConfig()); } Loading Loading @@ -849,6 +854,7 @@ public class A2dpService extends ProfileService { Log.e(TAG, "disableOptionalCodecs: Codec status is null"); return; } updateLowLatencyAudioSupport(device); mA2dpCodecConfig.disableOptionalCodecs(device, codecStatus.getCodecConfig()); } Loading Loading @@ -1208,6 +1214,34 @@ public class A2dpService extends ProfileService { } } /** * Check for low-latency codec support and inform AdapterService * * @param device device whose audio low latency will be allowed or disallowed */ @VisibleForTesting public void updateLowLatencyAudioSupport(BluetoothDevice device) { synchronized (mStateMachines) { A2dpStateMachine sm = mStateMachines.get(device); if (sm == null) { return; } BluetoothCodecStatus codecStatus = sm.getCodecStatus(); boolean lowLatencyAudioAllow = false; BluetoothCodecConfig lowLatencyCodec = new BluetoothCodecConfig.Builder() .setCodecType(SOURCE_CODEC_TYPE_OPUS) // remove in U .build(); if (codecStatus != null && codecStatus.isCodecConfigSelectable(lowLatencyCodec) && getOptionalCodecsEnabled(device) == BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) { lowLatencyAudioAllow = true; } mAdapterService.allowLowLatencyAudio(lowLatencyAudioAllow, device); } } private void connectionStateChanged(BluetoothDevice device, int fromState, int toState) { if ((device == null) || (fromState == toState)) { return; Loading
android/app/src/com/android/bluetooth/a2dp/A2dpStateMachine.java +2 −0 Original line number Diff line number Diff line Loading @@ -483,6 +483,7 @@ final class A2dpStateMachine extends StateMachine { // codecs (perhaps it's had a firmware update, etc.) and save that state if // it differs from what we had saved before. mA2dpService.updateOptionalCodecsSupport(mDevice); mA2dpService.updateLowLatencyAudioSupport(mDevice); broadcastConnectionState(mConnectionState, mLastConnectionState); // Upon connected, the audio starts out as stopped broadcastAudioState(BluetoothA2dp.STATE_NOT_PLAYING, Loading Loading @@ -655,6 +656,7 @@ final class A2dpStateMachine extends StateMachine { // for this codec change event. mA2dpService.updateOptionalCodecsSupport(mDevice); } mA2dpService.updateLowLatencyAudioSupport(mDevice); if (mA2dpOffloadEnabled) { boolean update = false; BluetoothCodecConfig newCodecConfig = mCodecStatus.getCodecConfig(); Loading
android/app/tests/unit/src/com/android/bluetooth/a2dp/A2dpStateMachineTest.java +15 −0 Original line number Diff line number Diff line Loading @@ -362,6 +362,7 @@ public class A2dpStateMachineTest { // Selected codec = SBC, selectable codec = SBC mA2dpStateMachine.processCodecConfigEvent(codecStatusSbcAndSbc); verify(mA2dpService).codecConfigUpdated(mTestDevice, codecStatusSbcAndSbc, false); verify(mA2dpService, times(1)).updateLowLatencyAudioSupport(mTestDevice); // Inject an event to change state machine to connected state A2dpStackEvent connStCh = Loading @@ -379,6 +380,7 @@ public class A2dpStateMachineTest { // Verify that state machine update optional codec when enter connected state verify(mA2dpService, times(1)).updateOptionalCodecsSupport(mTestDevice); verify(mA2dpService, times(2)).updateLowLatencyAudioSupport(mTestDevice); // Change codec status when device connected. // Selected codec = SBC, selectable codec = SBC+AAC Loading @@ -387,12 +389,14 @@ public class A2dpStateMachineTest { verify(mA2dpService).codecConfigUpdated(mTestDevice, codecStatusSbcAndSbcAac, true); } verify(mA2dpService, times(2)).updateOptionalCodecsSupport(mTestDevice); verify(mA2dpService, times(3)).updateLowLatencyAudioSupport(mTestDevice); // Update selected codec with selectable codec unchanged. // Selected codec = AAC, selectable codec = SBC+AAC mA2dpStateMachine.processCodecConfigEvent(codecStatusAacAndSbcAac); verify(mA2dpService).codecConfigUpdated(mTestDevice, codecStatusAacAndSbcAac, false); verify(mA2dpService, times(2)).updateOptionalCodecsSupport(mTestDevice); verify(mA2dpService, times(4)).updateLowLatencyAudioSupport(mTestDevice); // Update selected codec // Selected codec = OPUS, selectable codec = SBC+AAC+OPUS Loading @@ -401,5 +405,16 @@ public class A2dpStateMachineTest { verify(mA2dpService).codecConfigUpdated(mTestDevice, codecStatusOpusAndSbcAacOpus, true); } verify(mA2dpService, times(3)).updateOptionalCodecsSupport(mTestDevice); // Check if low latency audio been updated. verify(mA2dpService, times(5)).updateLowLatencyAudioSupport(mTestDevice); // Update selected codec with selectable codec changed. // Selected codec = SBC, selectable codec = SBC+AAC mA2dpStateMachine.processCodecConfigEvent(codecStatusSbcAndSbcAac); if (!offloadEnabled) { verify(mA2dpService).codecConfigUpdated(mTestDevice, codecStatusSbcAndSbcAac, true); } // Check if low latency audio been update. verify(mA2dpService, times(6)).updateLowLatencyAudioSupport(mTestDevice); } }