-
Notifications
You must be signed in to change notification settings - Fork 71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add audio usage type so it's possible to force audio from earpiece speaker #105
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please add a newline at the end of the file. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.doublesymmetry.kotlinaudio.models | ||
|
||
enum class AudioUsageType { | ||
MEDIA, | ||
VOICE_COMMUNICATION, | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. perhaps |
||
interceptPlayerActionsTriggeredExternally = playerConfig.interceptPlayerActionsTriggeredExternally, | ||
handleAudioBecomingNoisy = playerConfig.handleAudioBecomingNoisy, | ||
wakeMode = playerConfig.wakeMode, | ||
|
||
handleAudioFocus = audioAttributeConfig.handleAudioFocus, | ||
audioUsageType = audioAttributeConfig.audioUsageType, | ||
audioContentType = audioAttributeConfig.audioContentType, | ||
) | ||
|
||
setAudioAttributes() | ||
} | ||
} | ||
|
||
private fun setAudioAttributes() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't personally love the function overloading here. Perhaps we could name this function something like |
||
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() { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit on the fence about introducing this intermediate class just to encapsulate the arguments passed to the setAudio function. @dcvz will need to weigh in on it.