Loading packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteriaTest.kt +32 −23 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.systemui.volume.panel.component.spatial.domain import android.media.AudioDeviceAttributes import android.media.AudioDeviceInfo import android.media.session.MediaSession import android.media.session.PlaybackState import android.testing.TestableLooper.RunWithLooper Loading Loading @@ -49,26 +51,27 @@ import org.junit.runner.RunWith class SpatialAudioAvailabilityCriteriaTest : SysuiTestCase() { private val kosmos = testKosmos() private val cachedBluetoothDevice: CachedBluetoothDevice = mock { whenever(address).thenReturn("test_address") } private val bluetoothMediaDevice: BluetoothMediaDevice = mock { whenever(cachedDevice).thenReturn(cachedBluetoothDevice) } private lateinit var underTest: SpatialAudioAvailabilityCriteria @Before fun setup() { with(kosmos) { mediaControllerRepository.setActiveLocalMediaController( mediaController.apply { whenever(packageName).thenReturn("test.pkg") whenever(sessionToken).thenReturn(MediaSession.Token(0, mock {})) whenever(playbackState).thenReturn(PlaybackState.Builder().build()) val cachedBluetoothDevice: CachedBluetoothDevice = mock { whenever(address).thenReturn("test_address") } localMediaRepository.updateCurrentConnectedDevice( mock<BluetoothMediaDevice> { whenever(name).thenReturn("test_device") whenever(cachedDevice).thenReturn(cachedBluetoothDevice) } ) whenever(mediaController.packageName).thenReturn("test.pkg") whenever(mediaController.sessionToken).thenReturn(MediaSession.Token(0, mock {})) whenever(mediaController.playbackState).thenReturn(PlaybackState.Builder().build()) mediaControllerRepository.setActiveLocalMediaController(mediaController) underTest = SpatialAudioAvailabilityCriteria(spatialAudioComponentInteractor) } } Loading @@ -77,9 +80,8 @@ class SpatialAudioAvailabilityCriteriaTest : SysuiTestCase() { fun noSpatialAudio_noHeadTracking_unavailable() { with(kosmos) { testScope.runTest { localMediaRepository.updateCurrentConnectedDevice(bluetoothMediaDevice) spatializerRepository.defaultHeadTrackingAvailable = false spatializerRepository.defaultSpatialAudioAvailable = false spatializerRepository.setIsSpatialAudioAvailable(headset, false) spatializerRepository.setIsHeadTrackingAvailable(headset, false) val isAvailable by collectLastValue(underTest.isAvailable()) runCurrent() Loading @@ -93,9 +95,8 @@ class SpatialAudioAvailabilityCriteriaTest : SysuiTestCase() { fun spatialAudio_noHeadTracking_available() { with(kosmos) { testScope.runTest { localMediaRepository.updateCurrentConnectedDevice(bluetoothMediaDevice) spatializerRepository.defaultHeadTrackingAvailable = false spatializerRepository.defaultSpatialAudioAvailable = true spatializerRepository.setIsSpatialAudioAvailable(headset, true) spatializerRepository.setIsHeadTrackingAvailable(headset, false) val isAvailable by collectLastValue(underTest.isAvailable()) runCurrent() Loading @@ -109,9 +110,8 @@ class SpatialAudioAvailabilityCriteriaTest : SysuiTestCase() { fun spatialAudio_headTracking_available() { with(kosmos) { testScope.runTest { localMediaRepository.updateCurrentConnectedDevice(bluetoothMediaDevice) spatializerRepository.defaultHeadTrackingAvailable = true spatializerRepository.defaultSpatialAudioAvailable = true spatializerRepository.setIsSpatialAudioAvailable(headset, true) spatializerRepository.setIsHeadTrackingAvailable(headset, true) val isAvailable by collectLastValue(underTest.isAvailable()) runCurrent() Loading @@ -125,8 +125,8 @@ class SpatialAudioAvailabilityCriteriaTest : SysuiTestCase() { fun spatialAudio_headTracking_noDevice_unavailable() { with(kosmos) { testScope.runTest { spatializerRepository.defaultHeadTrackingAvailable = true spatializerRepository.defaultSpatialAudioAvailable = true localMediaRepository.updateCurrentConnectedDevice(null) spatializerRepository.setIsSpatialAudioAvailable(headset, false) val isAvailable by collectLastValue(underTest.isAvailable()) runCurrent() Loading @@ -135,4 +135,13 @@ class SpatialAudioAvailabilityCriteriaTest : SysuiTestCase() { } } } private companion object { val headset = AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLE_HEADSET, "test_address" ) } } packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt +91 −10 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import androidx.test.filters.SmallTest import com.android.settingslib.bluetooth.CachedBluetoothDevice import com.android.settingslib.media.BluetoothMediaDevice import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.kosmos.testScope import com.android.systemui.media.spatializerInteractor Loading @@ -37,6 +38,7 @@ import com.android.systemui.volume.localMediaRepository import com.android.systemui.volume.mediaController import com.android.systemui.volume.mediaControllerRepository import com.android.systemui.volume.mediaOutputInteractor import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioAvailabilityModel import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioEnabledModel import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi Loading Loading @@ -74,16 +76,6 @@ class SpatialAudioComponentInteractorTest : SysuiTestCase() { mediaControllerRepository.setActiveLocalMediaController(mediaController) spatializerRepository.setIsSpatialAudioAvailable( AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLE_HEADSET, "test_address" ), true ) spatializerRepository.defaultHeadTrackingAvailable = true underTest = SpatialAudioComponentInteractor( mediaOutputInteractor, Loading @@ -97,6 +89,7 @@ class SpatialAudioComponentInteractorTest : SysuiTestCase() { fun setEnabled_changesIsEnabled() { with(kosmos) { testScope.runTest { spatializerRepository.setIsSpatialAudioAvailable(headset, true) val values by collectValues(underTest.isEnabled) underTest.setEnabled(SpatialAudioEnabledModel.Disabled) Loading @@ -117,4 +110,92 @@ class SpatialAudioComponentInteractorTest : SysuiTestCase() { } } } @Test fun connectedDeviceSupports_isAvailable_SpatialAudio() { with(kosmos) { testScope.runTest { spatializerRepository.setIsSpatialAudioAvailable(headset, true) val isAvailable by collectLastValue(underTest.isAvailable) assertThat(isAvailable) .isInstanceOf(SpatialAudioAvailabilityModel.SpatialAudio::class.java) } } } @Test fun connectedDeviceSupportsHeadTracking_isAvailable_HeadTracking() { with(kosmos) { testScope.runTest { spatializerRepository.setIsSpatialAudioAvailable(headset, true) spatializerRepository.setIsHeadTrackingAvailable(headset, true) val isAvailable by collectLastValue(underTest.isAvailable) assertThat(isAvailable) .isInstanceOf(SpatialAudioAvailabilityModel.HeadTracking::class.java) } } } @Test fun connectedDeviceDoesntSupport_isAvailable_Unavailable() { with(kosmos) { testScope.runTest { spatializerRepository.setIsSpatialAudioAvailable(headset, false) val isAvailable by collectLastValue(underTest.isAvailable) assertThat(isAvailable) .isInstanceOf(SpatialAudioAvailabilityModel.Unavailable::class.java) } } } @Test fun noConnectedDeviceBuiltinSupports_isAvailable_SpatialAudio() { with(kosmos) { testScope.runTest { localMediaRepository.updateCurrentConnectedDevice(null) spatializerRepository.setIsSpatialAudioAvailable(builtinSpeaker, true) val isAvailable by collectLastValue(underTest.isAvailable) assertThat(isAvailable) .isInstanceOf(SpatialAudioAvailabilityModel.SpatialAudio::class.java) } } } @Test fun noConnectedDeviceBuiltinDoesntSupport_isAvailable_Unavailable() { with(kosmos) { testScope.runTest { localMediaRepository.updateCurrentConnectedDevice(null) spatializerRepository.setIsSpatialAudioAvailable(builtinSpeaker, false) val isAvailable by collectLastValue(underTest.isAvailable) assertThat(isAvailable) .isInstanceOf(SpatialAudioAvailabilityModel.Unavailable::class.java) } } } private companion object { val headset = AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLE_HEADSET, "test_address" ) val builtinSpeaker = AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "" ) } } packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt +48 −34 Original line number Diff line number Diff line Loading @@ -18,8 +18,9 @@ package com.android.systemui.volume.panel.component.spatial.domain.interactor import android.media.AudioDeviceAttributes import android.media.AudioDeviceInfo import com.android.settingslib.bluetooth.CachedBluetoothDevice import com.android.settingslib.media.BluetoothMediaDevice import com.android.settingslib.media.MediaDevice import com.android.settingslib.media.PhoneMediaDevice import com.android.settingslib.media.domain.interactor.SpatializerInteractor import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioAvailabilityModel Loading Loading @@ -54,12 +55,9 @@ constructor( private val currentAudioDeviceAttributes: StateFlow<AudioDeviceAttributes?> = mediaOutputInteractor.currentConnectedDevice .map { mediaDevice -> mediaDevice ?: return@map null val btDevice: CachedBluetoothDevice = (mediaDevice as? BluetoothMediaDevice)?.cachedDevice ?: return@map null btDevice.getAudioDeviceAttributes() if (mediaDevice == null) builtinSpeaker else mediaDevice.getAudioDeviceAttributes() } .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), null) .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), builtinSpeaker) /** * Returns spatial audio availability model. It can be: Loading Loading @@ -137,34 +135,50 @@ constructor( changes.emit(Unit) } private suspend fun CachedBluetoothDevice.getAudioDeviceAttributes(): AudioDeviceAttributes? { private suspend fun MediaDevice.getAudioDeviceAttributes(): AudioDeviceAttributes? { when (this) { is PhoneMediaDevice -> return builtinSpeaker is BluetoothMediaDevice -> { val device = cachedDevice ?: return null return listOf( AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLE_HEADSET, address device.address, ), AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLE_SPEAKER, address device.address, ), AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLE_BROADCAST, address device.address, ), AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, address device.address, ), AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_HEARING_AID, address device.address, ) ) .firstOrNull { spatializerInteractor.isSpatialAudioAvailable(it) } } else -> return null } } private companion object { val builtinSpeaker = AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "" ) } } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteriaTest.kt +32 −23 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.systemui.volume.panel.component.spatial.domain import android.media.AudioDeviceAttributes import android.media.AudioDeviceInfo import android.media.session.MediaSession import android.media.session.PlaybackState import android.testing.TestableLooper.RunWithLooper Loading Loading @@ -49,26 +51,27 @@ import org.junit.runner.RunWith class SpatialAudioAvailabilityCriteriaTest : SysuiTestCase() { private val kosmos = testKosmos() private val cachedBluetoothDevice: CachedBluetoothDevice = mock { whenever(address).thenReturn("test_address") } private val bluetoothMediaDevice: BluetoothMediaDevice = mock { whenever(cachedDevice).thenReturn(cachedBluetoothDevice) } private lateinit var underTest: SpatialAudioAvailabilityCriteria @Before fun setup() { with(kosmos) { mediaControllerRepository.setActiveLocalMediaController( mediaController.apply { whenever(packageName).thenReturn("test.pkg") whenever(sessionToken).thenReturn(MediaSession.Token(0, mock {})) whenever(playbackState).thenReturn(PlaybackState.Builder().build()) val cachedBluetoothDevice: CachedBluetoothDevice = mock { whenever(address).thenReturn("test_address") } localMediaRepository.updateCurrentConnectedDevice( mock<BluetoothMediaDevice> { whenever(name).thenReturn("test_device") whenever(cachedDevice).thenReturn(cachedBluetoothDevice) } ) whenever(mediaController.packageName).thenReturn("test.pkg") whenever(mediaController.sessionToken).thenReturn(MediaSession.Token(0, mock {})) whenever(mediaController.playbackState).thenReturn(PlaybackState.Builder().build()) mediaControllerRepository.setActiveLocalMediaController(mediaController) underTest = SpatialAudioAvailabilityCriteria(spatialAudioComponentInteractor) } } Loading @@ -77,9 +80,8 @@ class SpatialAudioAvailabilityCriteriaTest : SysuiTestCase() { fun noSpatialAudio_noHeadTracking_unavailable() { with(kosmos) { testScope.runTest { localMediaRepository.updateCurrentConnectedDevice(bluetoothMediaDevice) spatializerRepository.defaultHeadTrackingAvailable = false spatializerRepository.defaultSpatialAudioAvailable = false spatializerRepository.setIsSpatialAudioAvailable(headset, false) spatializerRepository.setIsHeadTrackingAvailable(headset, false) val isAvailable by collectLastValue(underTest.isAvailable()) runCurrent() Loading @@ -93,9 +95,8 @@ class SpatialAudioAvailabilityCriteriaTest : SysuiTestCase() { fun spatialAudio_noHeadTracking_available() { with(kosmos) { testScope.runTest { localMediaRepository.updateCurrentConnectedDevice(bluetoothMediaDevice) spatializerRepository.defaultHeadTrackingAvailable = false spatializerRepository.defaultSpatialAudioAvailable = true spatializerRepository.setIsSpatialAudioAvailable(headset, true) spatializerRepository.setIsHeadTrackingAvailable(headset, false) val isAvailable by collectLastValue(underTest.isAvailable()) runCurrent() Loading @@ -109,9 +110,8 @@ class SpatialAudioAvailabilityCriteriaTest : SysuiTestCase() { fun spatialAudio_headTracking_available() { with(kosmos) { testScope.runTest { localMediaRepository.updateCurrentConnectedDevice(bluetoothMediaDevice) spatializerRepository.defaultHeadTrackingAvailable = true spatializerRepository.defaultSpatialAudioAvailable = true spatializerRepository.setIsSpatialAudioAvailable(headset, true) spatializerRepository.setIsHeadTrackingAvailable(headset, true) val isAvailable by collectLastValue(underTest.isAvailable()) runCurrent() Loading @@ -125,8 +125,8 @@ class SpatialAudioAvailabilityCriteriaTest : SysuiTestCase() { fun spatialAudio_headTracking_noDevice_unavailable() { with(kosmos) { testScope.runTest { spatializerRepository.defaultHeadTrackingAvailable = true spatializerRepository.defaultSpatialAudioAvailable = true localMediaRepository.updateCurrentConnectedDevice(null) spatializerRepository.setIsSpatialAudioAvailable(headset, false) val isAvailable by collectLastValue(underTest.isAvailable()) runCurrent() Loading @@ -135,4 +135,13 @@ class SpatialAudioAvailabilityCriteriaTest : SysuiTestCase() { } } } private companion object { val headset = AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLE_HEADSET, "test_address" ) } }
packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt +91 −10 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import androidx.test.filters.SmallTest import com.android.settingslib.bluetooth.CachedBluetoothDevice import com.android.settingslib.media.BluetoothMediaDevice import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.kosmos.testScope import com.android.systemui.media.spatializerInteractor Loading @@ -37,6 +38,7 @@ import com.android.systemui.volume.localMediaRepository import com.android.systemui.volume.mediaController import com.android.systemui.volume.mediaControllerRepository import com.android.systemui.volume.mediaOutputInteractor import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioAvailabilityModel import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioEnabledModel import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi Loading Loading @@ -74,16 +76,6 @@ class SpatialAudioComponentInteractorTest : SysuiTestCase() { mediaControllerRepository.setActiveLocalMediaController(mediaController) spatializerRepository.setIsSpatialAudioAvailable( AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLE_HEADSET, "test_address" ), true ) spatializerRepository.defaultHeadTrackingAvailable = true underTest = SpatialAudioComponentInteractor( mediaOutputInteractor, Loading @@ -97,6 +89,7 @@ class SpatialAudioComponentInteractorTest : SysuiTestCase() { fun setEnabled_changesIsEnabled() { with(kosmos) { testScope.runTest { spatializerRepository.setIsSpatialAudioAvailable(headset, true) val values by collectValues(underTest.isEnabled) underTest.setEnabled(SpatialAudioEnabledModel.Disabled) Loading @@ -117,4 +110,92 @@ class SpatialAudioComponentInteractorTest : SysuiTestCase() { } } } @Test fun connectedDeviceSupports_isAvailable_SpatialAudio() { with(kosmos) { testScope.runTest { spatializerRepository.setIsSpatialAudioAvailable(headset, true) val isAvailable by collectLastValue(underTest.isAvailable) assertThat(isAvailable) .isInstanceOf(SpatialAudioAvailabilityModel.SpatialAudio::class.java) } } } @Test fun connectedDeviceSupportsHeadTracking_isAvailable_HeadTracking() { with(kosmos) { testScope.runTest { spatializerRepository.setIsSpatialAudioAvailable(headset, true) spatializerRepository.setIsHeadTrackingAvailable(headset, true) val isAvailable by collectLastValue(underTest.isAvailable) assertThat(isAvailable) .isInstanceOf(SpatialAudioAvailabilityModel.HeadTracking::class.java) } } } @Test fun connectedDeviceDoesntSupport_isAvailable_Unavailable() { with(kosmos) { testScope.runTest { spatializerRepository.setIsSpatialAudioAvailable(headset, false) val isAvailable by collectLastValue(underTest.isAvailable) assertThat(isAvailable) .isInstanceOf(SpatialAudioAvailabilityModel.Unavailable::class.java) } } } @Test fun noConnectedDeviceBuiltinSupports_isAvailable_SpatialAudio() { with(kosmos) { testScope.runTest { localMediaRepository.updateCurrentConnectedDevice(null) spatializerRepository.setIsSpatialAudioAvailable(builtinSpeaker, true) val isAvailable by collectLastValue(underTest.isAvailable) assertThat(isAvailable) .isInstanceOf(SpatialAudioAvailabilityModel.SpatialAudio::class.java) } } } @Test fun noConnectedDeviceBuiltinDoesntSupport_isAvailable_Unavailable() { with(kosmos) { testScope.runTest { localMediaRepository.updateCurrentConnectedDevice(null) spatializerRepository.setIsSpatialAudioAvailable(builtinSpeaker, false) val isAvailable by collectLastValue(underTest.isAvailable) assertThat(isAvailable) .isInstanceOf(SpatialAudioAvailabilityModel.Unavailable::class.java) } } } private companion object { val headset = AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLE_HEADSET, "test_address" ) val builtinSpeaker = AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "" ) } }
packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt +48 −34 Original line number Diff line number Diff line Loading @@ -18,8 +18,9 @@ package com.android.systemui.volume.panel.component.spatial.domain.interactor import android.media.AudioDeviceAttributes import android.media.AudioDeviceInfo import com.android.settingslib.bluetooth.CachedBluetoothDevice import com.android.settingslib.media.BluetoothMediaDevice import com.android.settingslib.media.MediaDevice import com.android.settingslib.media.PhoneMediaDevice import com.android.settingslib.media.domain.interactor.SpatializerInteractor import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioAvailabilityModel Loading Loading @@ -54,12 +55,9 @@ constructor( private val currentAudioDeviceAttributes: StateFlow<AudioDeviceAttributes?> = mediaOutputInteractor.currentConnectedDevice .map { mediaDevice -> mediaDevice ?: return@map null val btDevice: CachedBluetoothDevice = (mediaDevice as? BluetoothMediaDevice)?.cachedDevice ?: return@map null btDevice.getAudioDeviceAttributes() if (mediaDevice == null) builtinSpeaker else mediaDevice.getAudioDeviceAttributes() } .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), null) .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), builtinSpeaker) /** * Returns spatial audio availability model. It can be: Loading Loading @@ -137,34 +135,50 @@ constructor( changes.emit(Unit) } private suspend fun CachedBluetoothDevice.getAudioDeviceAttributes(): AudioDeviceAttributes? { private suspend fun MediaDevice.getAudioDeviceAttributes(): AudioDeviceAttributes? { when (this) { is PhoneMediaDevice -> return builtinSpeaker is BluetoothMediaDevice -> { val device = cachedDevice ?: return null return listOf( AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLE_HEADSET, address device.address, ), AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLE_SPEAKER, address device.address, ), AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLE_BROADCAST, address device.address, ), AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, address device.address, ), AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_HEARING_AID, address device.address, ) ) .firstOrNull { spatializerInteractor.isSpatialAudioAvailable(it) } } else -> return null } } private companion object { val builtinSpeaker = AudioDeviceAttributes( AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "" ) } }