Comments (3)
Thanks for your report.
We are using media3 library to send voice commands to the media outlet.
Can you clarify a bit what Media3 API you are using to send a voice command from your app to another app? I don't know how this works I'm afraid.
Best would probably be to extend the the repro steps to make them tell what API is called to pause/play another app with Media3.
from media.
Hey @akrulec. We need more information to resolve this issue but there hasn't been an update in 14 weekdays. I'm marking the issue as stale and if there are no new updates in the next 7 days I will close it automatically.
If you have more information that will help us get to the bottom of this, just add a comment!
from media.
We are using ExoPlayer from media3 to play voice commands to the user while they are going through a routine. Each time we speak a voice command, we request focus, play our mp4, and then give away focus when the audio is done (usually short 1-8sec). If the user connects to the phone via bluetooth, and they are listening to anything in the background, the background music ducks or stops, but after a while, there is a bluetooth crash, and the background music never resumes.
import androidx.media3.common.AudioAttributes
import androidx.media3.common.C
import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlaybackException
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
import androidx.media3.session.MediaSession
import androidx.media3.session.MediaSessionService
AudioPlayerService : MediaSessionService()
private var exoPlayer: ExoPlayer? = null
private var mediaSession: MediaSession? = null
private var currentItem: AudioQueueItem? = null
private val audioAttributes =
AudioAttributes.Builder()
// Cannot use C.USAGE_ASSISTANT here because it connects to Bixby on Samsung phones, and
// it makes it impossible to adjust when the media is playing in the background. I
// suspect it connects to AudioSystem.STREAM_ASSISTANT which is not publicly available.
.setUsage(C.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
.setContentType(C.AUDIO_CONTENT_TYPE_SPEECH)
.build()
// Lock for all adding and removing media operations. This seems to have fixed the issue when
// sometimes the media is not ducking.
private val focusLock = Any()
// Check whether the playback is delayed, because audio focus was not granted.
private var playbackDelayed = false
// Variable to keep track on whether the playback should be continued when the focus is
// regained.
private var resumeOnFocusGain = false
// Audio focus listener with the help from here:
// https://developer.android.com/reference/android/media/AudioFocusRequest
private val onAudioFocusChangeListener =
AudioManager.OnAudioFocusChangeListener { focusChange ->
when (focusChange) {
AudioManager.AUDIOFOCUS_GAIN -> {
if (playbackDelayed || resumeOnFocusGain) {
synchronized(focusLock) {
playbackDelayed = false
resumeOnFocusGain = false
}
playbackNow()
}
}
AudioManager.AUDIOFOCUS_LOSS -> {
synchronized(focusLock) {
// This is not a transient loss, we shouldn't automatically resume for now.
resumeOnFocusGain = false
playbackDelayed = false
}
duckPlayback()
}
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT,
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
// Handle all transient losses the same way because we never duck.
synchronized(focusLock) {
// We should only resume if playback was interrupted.
resumeOnFocusGain = exoPlayer?.isPlaying ?: false
playbackDelayed = false
}
duckPlayback()
}
}
}
@OptIn(UnstableApi::class)
override fun onCreate() {
super.onCreate()
exoPlayer =
ExoPlayer.Builder(this)
.setAudioAttributes(audioAttributes, false)
.setMediaSourceFactory(
DefaultMediaSourceFactory(coPilotDownloadManager.cachedMediaSourceFactory))
.build()
exoPlayer?.also {
it.addListener(playerListener)
it.playWhenReady = true
it.setWakeMode(PowerManager.PARTIAL_WAKE_LOCK)
it.prepare()
setVolume()
}
audioManager = applicationContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager
val audioAttributes =
android.media.AudioAttributes.Builder()
.setUsage(android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
.setContentType(android.media.AudioAttributes.CONTENT_TYPE_SPEECH)
.build()
focusRequest =
AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
.setAcceptsDelayedFocusGain(false)
.setAudioAttributes(audioAttributes)
.setForceDucking(true)
.setOnAudioFocusChangeListener(onAudioFocusChangeListener)
.build()
exoPlayer?.let { mediaSession = MediaSession.Builder(applicationContext, it).build() }
acquireWifiLock()
}
....
currentItem?.let { item ->
if (audioManager != null && focusRequest != null) {
// Requesting audio focus.
val res = audioManager!!.requestAudioFocus(focusRequest!!)
synchronized(focusLock) {
focusRequested = true
when (res) {
AudioManager.AUDIOFOCUS_REQUEST_FAILED -> {
playbackDelayed = false
}
AudioManager.AUDIOFOCUS_REQUEST_GRANTED -> {
playbackDelayed = false
playbackNow(item.url)
}
AudioManager.AUDIOFOCUS_REQUEST_DELAYED -> {
playbackDelayed = true
}
}
}
}
}
...
/** Clears media from the player and abandons focus. */
fun clearMedia() {
synchronized(focusLock) {
// First abandon focus.
if (audioManager != null && focusRequest != null && focusRequested) {
audioManager!!.abandonAudioFocusRequest(focusRequest!!)
synchronized(focusLock) { focusRequested = false }
}
// Then clear the media.
resumeOnFocusGain = false
exoPlayer?.clearMediaItems()
}
}
/** Plays the given URL or resumes the exo player if there is anything to play. */
@OptIn(UnstableApi::class)
private fun playbackNow(url: String? = null) {
// Play new item or continue playing.
url?.let {
exoPlayer?.addMediaSource(coPilotDownloadManager.buildMediaSourceFromUrl(it))
}
setVolume()
exoPlayer?.play()
}
/** Pauses the audio. Used when other apps request audio duck. */
private fun duckPlayback() {
val volume = SharedPreferencesUtil.getVoiceInstructionsVolume(applicationContext)
// Volume comes in 1-100, and ExoPlayer accepts 0-1. Multiply with duck to talk in the back.
exoPlayer?.volume = (volume / MAX_VOLUME) * DUCK_VOLUME
}
private fun acquireWifiLock() {
if (wifiLock == null) {
val wifiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager
wifiLock =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
wifiManager.createWifiLock(
WifiManager.WIFI_MODE_FULL_LOW_LATENCY, "coPilot_lock")
} else {
wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "coPilot_lock")
}
}
wifiLock?.acquire()
}
private fun releaseWifiLock() {
wifiLock?.release()
}
private inner class PlayerEventListener : Player.Listener {
override fun onPlaybackStateChanged(playbackState: Int) {
when (playbackState) {
Player.STATE_ENDED -> {
// Only clear focus when no new items to play.
if (audioManager != null &&
focusRequest != null &&
focusRequested &&
(listener?.isQueueEmpty() == true)) {
audioManager!!.abandonAudioFocusRequest(focusRequest!!)
synchronized(focusLock) { focusRequested = false }
}
// Clear the media items, and reset the player.
// Unsure if this needs to happen here or in the STATE_READY.
exoPlayer?.clearMediaItems()
exoPlayer?.seekToDefaultPosition()
mediaReady()
}
Player.STATE_BUFFERING,
Player.STATE_IDLE,
Player.STATE_READY -> {
// Don't do anything for now.
}
}
}
Dependencies
version_media = "1.2.0"
implementation "androidx.media3:media3-exoplayer:$version_media"
implementation "androidx.media3:media3-session:$version_media"
from media.
Related Issues (20)
- Packaging Widevine for key rotation HOT 4
- CSAI ads with IMA for live stream? HOT 1
- [Transformer] The color of BitmapOverlay is a little off HOT 17
- Not selecting the correct video track for the video exported from Pixel8 captured motion JPEG HOT 5
- DRM Problem (VR Split Screen with Multiple SurfaceView) HOT 4
- Output switcher appears broken after switching to CastPlayer HOT 8
- FMP4 Multiple Media Sources Seamless seek HOT 3
- Ability to set Dialog for TrackSelectionDialogBuilder HOT 4
- Killing the app while audio is playing results in "The controller is not connected" and not being able to play again HOT 14
- Battery HOT 3
- Loading custom shaders in media player? HOT 1
- Audio stops playing, the player doesn't stop nor reports an error HOT 2
- How to Add subtitle files or url during playing ? HOT 2
- Playback Resumption with external applications HOT 2
- Videos filmed vertically are rotated 90 degrees on Android 9
- Problem with skippable pre-roll ads when seeking the player to resume a playback HOT 2
- Is it possible with media3 to replace the MediaMetadataRetriever thumbnail extraction functionality? HOT 1
- last frame is black when show VAST ads HOT 13
- DecoderCounters reset before `onVideoDisabled()` is delivered. HOT 1
- Broken playback resumption HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from media.