From ef73d82e8c62f55e4c77be9769451cf8cda782bf Mon Sep 17 00:00:00 2001 From: Egbert-Jan Terpstra Date: Tue, 2 Apr 2024 15:19:20 +0200 Subject: [PATCH] feat: add audio usage type so it's possible to force audio from earpiece speaker --- .../models/AudioAttributesConfig.kt | 18 +++++ .../kotlinaudio/models/AudioUsageType.kt | 7 ++ .../kotlinaudio/models/PlayerConfig.kt | 4 ++ .../kotlinaudio/players/BaseAudioPlayer.kt | 66 ++++++++++++++----- 4 files changed, 80 insertions(+), 15 deletions(-) create mode 100644 kotlin-audio/src/main/java/com/doublesymmetry/kotlinaudio/models/AudioAttributesConfig.kt create mode 100644 kotlin-audio/src/main/java/com/doublesymmetry/kotlinaudio/models/AudioUsageType.kt diff --git a/kotlin-audio/src/main/java/com/doublesymmetry/kotlinaudio/models/AudioAttributesConfig.kt b/kotlin-audio/src/main/java/com/doublesymmetry/kotlinaudio/models/AudioAttributesConfig.kt new file mode 100644 index 00000000..82151eea --- /dev/null +++ b/kotlin-audio/src/main/java/com/doublesymmetry/kotlinaudio/models/AudioAttributesConfig.kt @@ -0,0 +1,18 @@ +package com.doublesymmetry.kotlinaudio.models + +data class AudioAttributeConfig( + + /** + * Whether audio focus should be managed automatically. See https://medium.com/google-exoplayer/easy-audio-focus-with-exoplayer-a2dcbbe4640e + */ + val handleAudioFocus: Boolean = false, + /** + * The audio content type. + */ + val audioContentType: AudioContentType = AudioContentType.MUSIC, + + /** + * The audio usage type. + */ + var audioUsageType: AudioUsageType = AudioUsageType.MEDIA +) \ No newline at end of file diff --git a/kotlin-audio/src/main/java/com/doublesymmetry/kotlinaudio/models/AudioUsageType.kt b/kotlin-audio/src/main/java/com/doublesymmetry/kotlinaudio/models/AudioUsageType.kt new file mode 100644 index 00000000..0c41eca5 --- /dev/null +++ b/kotlin-audio/src/main/java/com/doublesymmetry/kotlinaudio/models/AudioUsageType.kt @@ -0,0 +1,7 @@ +package com.doublesymmetry.kotlinaudio.models + +enum class AudioUsageType { + MEDIA, + VOICE_COMMUNICATION, +} + diff --git a/kotlin-audio/src/main/java/com/doublesymmetry/kotlinaudio/models/PlayerConfig.kt b/kotlin-audio/src/main/java/com/doublesymmetry/kotlinaudio/models/PlayerConfig.kt index 74cb654e..62bc4086 100644 --- a/kotlin-audio/src/main/java/com/doublesymmetry/kotlinaudio/models/PlayerConfig.kt +++ b/kotlin-audio/src/main/java/com/doublesymmetry/kotlinaudio/models/PlayerConfig.kt @@ -24,6 +24,10 @@ data class PlayerConfig( * Whether audio focus should be managed automatically. See https://medium.com/google-exoplayer/easy-audio-focus-with-exoplayer-a2dcbbe4640e */ val handleAudioFocus: Boolean = false, + /** + * The audio usage type. + */ + val audioUsageType: AudioUsageType = AudioUsageType.MEDIA, /** * The audio content type. */ diff --git a/kotlin-audio/src/main/java/com/doublesymmetry/kotlinaudio/players/BaseAudioPlayer.kt b/kotlin-audio/src/main/java/com/doublesymmetry/kotlinaudio/players/BaseAudioPlayer.kt index 3bc4f1cc..4329480a 100644 --- a/kotlin-audio/src/main/java/com/doublesymmetry/kotlinaudio/players/BaseAudioPlayer.kt +++ b/kotlin-audio/src/main/java/com/doublesymmetry/kotlinaudio/players/BaseAudioPlayer.kt @@ -19,11 +19,13 @@ import androidx.media.AudioManagerCompat.AUDIOFOCUS_GAIN import com.doublesymmetry.kotlinaudio.event.EventHolder import com.doublesymmetry.kotlinaudio.event.NotificationEventHolder import com.doublesymmetry.kotlinaudio.event.PlayerEventHolder +import com.doublesymmetry.kotlinaudio.models.AudioAttributeConfig import com.doublesymmetry.kotlinaudio.models.AudioContentType import com.doublesymmetry.kotlinaudio.models.AudioItem import com.doublesymmetry.kotlinaudio.models.AudioItemHolder import com.doublesymmetry.kotlinaudio.models.AudioItemTransitionReason import com.doublesymmetry.kotlinaudio.models.AudioPlayerState +import com.doublesymmetry.kotlinaudio.models.AudioUsageType import com.doublesymmetry.kotlinaudio.models.BufferConfig import com.doublesymmetry.kotlinaudio.models.CacheConfig import com.doublesymmetry.kotlinaudio.models.DefaultPlayerOptions @@ -250,21 +252,8 @@ abstract class BaseAudioPlayer internal constructor( exoPlayer.addListener(PlayerListener()) scope.launch { - // Whether ExoPlayer should manage audio focus for us automatically - // see https://medium.com/google-exoplayer/easy-audio-focus-with-exoplayer-a2dcbbe4640e - val audioAttributes = AudioAttributes.Builder() - .setUsage(C.USAGE_MEDIA) - .setContentType( - when (playerConfig.audioContentType) { - AudioContentType.MUSIC -> C.AUDIO_CONTENT_TYPE_MUSIC - AudioContentType.SPEECH -> C.AUDIO_CONTENT_TYPE_SPEECH - AudioContentType.SONIFICATION -> C.AUDIO_CONTENT_TYPE_SONIFICATION - AudioContentType.MOVIE -> C.AUDIO_CONTENT_TYPE_MOVIE - AudioContentType.UNKNOWN -> C.AUDIO_CONTENT_TYPE_UNKNOWN - } - ) - .build(); - exoPlayer.setAudioAttributes(audioAttributes, playerConfig.handleAudioFocus); + setAudioAttributes() + mediaSessionConnector.setPlayer(playerToUse) mediaSessionConnector.setMediaMetadataProvider { notificationManager.getMediaMetadataCompat() @@ -274,6 +263,53 @@ abstract class BaseAudioPlayer internal constructor( playerEventHolder.updateAudioPlayerState(AudioPlayerState.IDLE) } + fun setAudioAttributes(audioAttributeConfig: AudioAttributeConfig) { + scope.launch { + playerConfig = PlayerConfig( + interceptPlayerActionsTriggeredExternally = playerConfig.interceptPlayerActionsTriggeredExternally, + handleAudioBecomingNoisy = playerConfig.handleAudioBecomingNoisy, + wakeMode = playerConfig.wakeMode, + + handleAudioFocus = audioAttributeConfig.handleAudioFocus, + audioUsageType = audioAttributeConfig.audioUsageType, + audioContentType = audioAttributeConfig.audioContentType, + ) + + setAudioAttributes() + } + } + + private fun setAudioAttributes() { + val audioAttributes = AudioAttributes.Builder() + .setUsage( + when (playerConfig.audioUsageType) { + AudioUsageType.MEDIA -> C.USAGE_MEDIA + AudioUsageType.VOICE_COMMUNICATION -> C.USAGE_VOICE_COMMUNICATION + } + ) + .setContentType( + when (playerConfig.audioContentType) { + AudioContentType.MUSIC -> C.AUDIO_CONTENT_TYPE_MUSIC + AudioContentType.SPEECH -> C.AUDIO_CONTENT_TYPE_SPEECH + AudioContentType.SONIFICATION -> C.AUDIO_CONTENT_TYPE_SONIFICATION + AudioContentType.MOVIE -> C.AUDIO_CONTENT_TYPE_MOVIE + AudioContentType.UNKNOWN -> C.AUDIO_CONTENT_TYPE_UNKNOWN + } + ) + .build(); + + try { + var handleAudioFocus = playerConfig.handleAudioFocus + if (audioAttributes.usage != C.USAGE_MEDIA || audioAttributes.usage != C.USAGE_GAME) { + handleAudioFocus = false + } + + exoPlayer.setAudioAttributes(audioAttributes, handleAudioFocus); + } catch (e: Exception) { + Timber.e("Error setting audioAttributes: ", e) + } + } + private fun createForwardingPlayer(): ForwardingPlayer { return object : ForwardingPlayer(exoPlayer) { override fun play() {