Deux applications Android ou plus peuvent lire du contenu audio sur le même flux de sortie simultanément, et le système mélange tout. Bien que ce soit techniquement impressionnant, cela peut être très agaçant pour un utilisateur. Pour éviter tous les d'une application musicale en même temps, Android introduit l'idée du contenu audio sélection. Une seule application peut conserver la priorité audio à la fois.
Lorsque votre application doit diffuser du contenu audio, elle doit demander la priorité audio. Lorsqu'il a il peut diffuser du son. Cependant, une fois la priorité audio acquise, jusqu'à ce que vous ayez fini de jouer. Une autre application peut demander la sélection, ce qui préempte votre mise en attente sur la priorité audio. Dans ce cas, votre application doit se mettre en pause. ou baisser le volume pour permettre aux utilisateurs d'entendre plus facilement la nouvelle source audio.
Avant Android 12 (niveau d'API 31), la priorité audio n'est pas gérée par le système. Donc, tandis que les développeurs d'applications sont encouragés à respecter les directives Si une application continue de fonctionner à un volume élevé même après avoir perdu la priorité audio sur un appareil exécutant Android 11 (niveau d'API 30) ou une version antérieure, le système ne peut pas l'empêcher. Cependant, ce comportement de l'application nuit à l'expérience utilisateur et peut souvent conduire aux utilisateurs de désinstaller l'application défaillante.
Une application audio bien conçue doit gérer la priorité audio en suivant ces consignes:
Appelez
requestAudioFocus()
juste avant de commencer à jouer et vérifiez que l'appel renvoieAUDIOFOCUS_REQUEST_GRANTED
AppelezrequestAudioFocus()
dans le rappelonPlay()
de votre session multimédia.Lorsqu'une autre application se concentre sur le son, arrête ou interrompt la lecture, ou diminue (c'est-à-dire réduire) le volume.
Lorsque la lecture s'arrête (par exemple, lorsque l'application n'a rien d'autre à lire) abandonne la priorité audio. Votre application ne doit pas abandonner la priorité audio si l'utilisateur suspend la lecture, mais peut la reprendre plus tard.
Utilisez
AudioAttributes
pour décrire le type de contenu audio lu par votre application. Par exemple, pour les applications qui diffusent de la voix, préciserCONTENT_TYPE_SPEECH
La priorité audio est gérée différemment selon la version d'Android est en cours d'exécution:
- Android 12 (niveau d'API 31) ou version ultérieure
- Le ciblage audio est géré par le système. Le système force la lecture audio à partir d'un pour faire disparaître l'application en fondu lorsqu'une autre application demande la priorité audio. Le système et coupe également le son de la lecture audio à la réception d'un appel.
- Android 8.0 (niveau d'API 26) à Android 11 (niveau d'API 30)
- Le ciblage audio n'est pas géré par le système, mais inclut des modifications Lancement à partir d'Android 8.0 (niveau d'API 26).
- Android 7.1 (niveau d'API 25) ou version antérieure
- Le ciblage audio n'est pas géré par le système, mais les applications le gèrent à l'aide de
la
requestAudioFocus()
etabandonAudioFocus()
Priorité audio sur Android 12 ou version ultérieure
Une appli multimédia ou de jeu qui utilise la priorité audio ne doit pas lire de contenu audio après avoir perdu le focus. Dans Android 12 (niveau d'API 31) ou version ultérieure, le système applique cette comportemental. Lorsqu'une application demande la priorité audio alors qu'une autre est ciblée et le système force la fermeture en fondu de l'application. L'ajout du paramètre Le fondu enchaîné offre une transition plus fluide lors du passage d'une application à une autre.
Ce comportement se produit lorsque les conditions suivantes sont remplies:
La première application en cours de lecture répond à tous ces critères:
- L'application dispose du paramètre
AudioAttributes.USAGE_MEDIA
ou Attribut d'utilisationAudioAttributes.USAGE_GAME
. - L'application a bien demandé la priorité audio avec
AudioManager.AUDIOFOCUS_GAIN
. - L'application ne lit pas de contenu audio de type
AudioAttributes.CONTENT_TYPE_SPEECH
.
- L'application dispose du paramètre
Une deuxième application demande la priorité audio avec
AudioManager.AUDIOFOCUS_GAIN
.
Lorsque ces conditions sont remplies, le système audio quitte la première application en fondu. Au fin du fondu, le système informe la première application qu'une perte de mise au point est détectée. L'application le son des joueurs reste coupé jusqu'à ce que l'application demande à nouveau la priorité audio.
Comportements de ciblage audio existants
Vous devez également être conscient de ces autres cas qui impliquent un changement dans l'audio le focus.
Atténuation automatique
Diminution automatique (réduction temporaire du volume audio d'une application pour que l'autre peut être entendue clairement) a été introduite dans Android 8.0 (niveau d'API 26).
En laissant le système implémenter la diminution, vous n'avez pas à implémenter votre application.
L'atténuation automatique se produit également lorsqu'une notification audio attire l'attention depuis une application de jeu. Le début de la lecture de la notification est synchronisé au bout de la rampe d'atténuation.
L'atténuation automatique se produit lorsque les conditions suivantes sont remplies:
La première application en cours de lecture répond à tous ces critères:
- L'application a bien demandé la priorité audio, quel que soit le type de ciblage gain de temps.
- L'application ne lit pas l'audio de ce type de contenu
AudioAttributes.CONTENT_TYPE_SPEECH
- L'application n'a pas été définie
AudioFocusRequest.Builder.setWillPauseWhenDucked(true)
Une deuxième application demande la priorité audio avec
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
Lorsque ces conditions sont remplies, le système audio bloque tous les joueurs actifs de la première application tandis que la deuxième est ciblée. Lorsque la deuxième application abandonne se concentrer, cela les éloigne. La première application n'est pas notifiée lorsqu'elle perd son focus. et n'a rien à faire.
Notez que la diminution automatique n'est pas effectuée lorsque l'utilisateur écoute contenu vocal, car l'utilisateur pourrait manquer une partie du programme. Par exemple : le guidage vocal pour les itinéraires routiers ne sont pas inclinés.
Couper le son de la lecture audio en cours pour les appels téléphoniques entrants
Certaines applications ne se comportent pas correctement et continuent de lire le contenu audio lors des appels téléphoniques. Cette situation oblige l'utilisateur à trouver et à couper le son de l'application en cause ou à la quitter dans pour entendre leur appel. Pour éviter cela, le système peut couper le son des autres pendant un appel entrant. Le système appelle cette fonctionnalité lorsqu'un lorsqu'un appel téléphonique entrant est reçu et qu'une application remplit les conditions suivantes:
- L'application dispose de l'
AudioAttributes.USAGE_MEDIA
ou Attribut d'utilisationAudioAttributes.USAGE_GAME
. - L'appli a bien demandé la priorité audio (tout gain de concentration) et la lecture est en cours audio.
Si la lecture d'une application se poursuit pendant l'appel, le son de la lecture est coupé jusqu'à ce que l'icône à la fin de l'appel. Toutefois, si la lecture d'une application démarre pendant l'appel, ce lecteur n'est pas en partant du principe que l'utilisateur a lancé la lecture intentionnellement.
Priorité audio dans Android 8.0 à Android 11
À partir d'Android 8.0 (niveau d'API 26), lorsque vous appelez
requestAudioFocus()
vous devez fournir un paramètre AudioFocusRequest
. AudioFocusRequest
contient des informations sur le contexte audio et les fonctionnalités de votre application. La
système utilise ces informations pour gérer le gain et la perte de priorité audio
automatiquement. Pour libérer le ciblage audio, appelez la méthode
abandonAudioFocusRequest()
qui utilise également un AudioFocusRequest
comme argument. Utiliser la même
AudioFocusRequest
lorsque vous demandez et abandonnez le focus.
Pour créer un AudioFocusRequest
, utilisez un
AudioFocusRequest.Builder
Étant donné qu'une demande
de focus doit
toujours spécifier le type de la requête, celui-ci est inclus dans le constructeur.
pour le compilateur. Utilisez les méthodes du compilateur pour définir les autres champs du
requête.
Le champ FocusGain
est obligatoire. tous les autres champs sont facultatifs.
Méthode | Notes |
---|---|
setFocusGain()
|
Ce champ est obligatoire dans chaque requête. Il a les mêmes valeurs que
durationHint utilisé dans l'appel à requestAudioFocus() antérieur à Android 8.0:
AUDIOFOCUS_GAIN , AUDIOFOCUS_GAIN_TRANSIENT
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK ou AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE .
|
setAudioAttributes()
|
AudioAttributes décrit le cas d'utilisation de votre application. La
lorsqu'une appli gagne ou perd sa priorité audio. Attributs
remplacer la notion
de type de flux. Sur Android 8.0 (niveau d'API 26) et versions ultérieures,
types de flux pour toute opération autre que le contrôle du volume sont obsolètes. Utilisez
les mêmes attributs dans la requête de focus que ceux utilisés dans votre lecteur audio (comme
comme indiqué dans l'exemple qui suit ce tableau).
Utilisez un
Si aucune valeur n'est spécifiée, |
setWillPauseWhenDucked()
|
Lorsqu'une autre application demande à sélectionner
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK , l'application sélectionnée ne
reçoivent généralement
onAudioFocusChange()
car le système peut effectuer le
tout seul. Lorsque vous avez besoin de mettre la lecture en pause plutôt que
que de baisser le volume, appelez setWillPauseWhenDucked(true) , puis créez et définissez une
OnAudioFocusChangeListener , comme décrit dans la section
en baisse.
|
setAcceptsDelayedFocusGain()
|
Une requête de ciblage audio peut échouer lorsque le ciblage est verrouillé par une autre application.
Cette méthode active le retrait de la focalisation, à savoir la capacité
d'obtenir le focus de manière asynchrone
lorsqu'il devient disponible.
Notez que le gain de mise au point différé ne fonctionne que si vous spécifiez également un
|
setOnAudioFocusChangeListener()
|
Un élément OnAudioFocusChangeListener n'est requis que si vous spécifiez également
willPauseWhenDucked(true) ou setAcceptsDelayedFocusGain(true) dans la requête.
Il existe deux méthodes pour définir l'écouteur: l'une avec et l'autre sans
l'argument "manager". Le gestionnaire est le thread sur lequel l'écouteur s'exécute. Si vous
ne spécifie pas de gestionnaire : le gestionnaire associé à l'instance principale
|
L'exemple suivant montre comment utiliser un AudioFocusRequest.Builder
pour compiler
un AudioFocusRequest
et la requête et l'abandon du ciblage audio:
Kotlin
// initializing variables for audio focus and playback management audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).run { setAudioAttributes(AudioAttributes.Builder().run { setUsage(AudioAttributes.USAGE_GAME) setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) build() }) setAcceptsDelayedFocusGain(true) setOnAudioFocusChangeListener(afChangeListener, handler) build() } val focusLock = Any() var playbackDelayed = false var playbackNowAuthorized = false // requesting audio focus and processing the response val res = audioManager.requestAudioFocus(focusRequest) synchronized(focusLock) { playbackNowAuthorized = when (res) { AudioManager.AUDIOFOCUS_REQUEST_FAILED -> false AudioManager.AUDIOFOCUS_REQUEST_GRANTED -> { playbackNow() true } AudioManager.AUDIOFOCUS_REQUEST_DELAYED -> { playbackDelayed = true false } else -> false } } // implementing OnAudioFocusChangeListener to react to focus changes override fun onAudioFocusChange(focusChange: Int) { when (focusChange) { AudioManager.AUDIOFOCUS_GAIN -> if (playbackDelayed || resumeOnFocusGain) { synchronized(focusLock) { playbackDelayed = false resumeOnFocusGain = false } playbackNow() } AudioManager.AUDIOFOCUS_LOSS -> { synchronized(focusLock) { resumeOnFocusGain = false playbackDelayed = false } pausePlayback() } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { synchronized(focusLock) { // only resume if playback is being interrupted resumeOnFocusGain = isPlaying() playbackDelayed = false } pausePlayback() } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { // ... pausing or ducking depends on your app } } }
Java
// initializing variables for audio focus and playback management audioManager = (AudioManager) Context.getSystemService(Context.AUDIO_SERVICE); playbackAttributes = new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_GAME) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .build(); focusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN) .setAudioAttributes(playbackAttributes) .setAcceptsDelayedFocusGain(true) .setOnAudioFocusChangeListener(afChangeListener, handler) .build(); final Object focusLock = new Object(); boolean playbackDelayed = false; boolean playbackNowAuthorized = false; // requesting audio focus and processing the response int res = audioManager.requestAudioFocus(focusRequest); synchronized(focusLock) { if (res == AudioManager.AUDIOFOCUS_REQUEST_FAILED) { playbackNowAuthorized = false; } else if (res == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { playbackNowAuthorized = true; playbackNow(); } else if (res == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) { playbackDelayed = true; playbackNowAuthorized = false; } } // implementing OnAudioFocusChangeListener to react to focus changes @Override public void onAudioFocusChange(int focusChange) { switch (focusChange) { case AudioManager.AUDIOFOCUS_GAIN: if (playbackDelayed || resumeOnFocusGain) { synchronized(focusLock) { playbackDelayed = false; resumeOnFocusGain = false; } playbackNow(); } break; case AudioManager.AUDIOFOCUS_LOSS: synchronized(focusLock) { resumeOnFocusGain = false; playbackDelayed = false; } pausePlayback(); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: synchronized(focusLock) { // only resume if playback is being interrupted resumeOnFocusGain = isPlaying(); playbackDelayed = false; } pausePlayback(); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // ... pausing or ducking depends on your app break; } } }
Atténuation automatique
Dans Android 8.0 (niveau d'API 26), lorsqu'une autre application demande à se concentrer avec
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
: le système peut baisser et restaurer le volume
sans appeler le rappel onAudioFocusChange()
de l'application.
Bien que la diminution automatique soit un comportement acceptable pour la lecture de musique et de vidéos applications, elle n'est pas utile lors de la lecture de contenus audio, application de livre audio. Dans ce cas, l'application doit se mettre en pause.
Si vous souhaitez que votre application se mette en pause lorsque vous êtes invité à baisser plutôt que de baisser le volume, créez une OnAudioFocusChangeListener
avec
Une méthode de rappel onAudioFocusChange()
qui implémente le comportement de mise en pause/reprise souhaité.
Appelez setOnAudioFocusChangeListener()
pour enregistrer l'écouteur, puis appelez
setWillPauseWhenDucked(true)
pour indiquer au système d'utiliser votre rappel plutôt que d'effectuer l'atténuation automatique.
Gain de concentration différé
Parfois, le système ne peut pas accorder de
demande de ciblage audio, car le focus est
"verrouillée" par une autre application, par exemple lors d'un appel téléphonique. Dans ce cas,
requestAudioFocus()
renvoie AUDIOFOCUS_REQUEST_FAILED
. Dans ce cas,
votre application ne doit pas poursuivre la lecture audio, car elle n'a pas
le focus.
La méthode setAcceptsDelayedFocusGain(true)
, qui permet à votre application de gérer une requête de sélection
de manière asynchrone. Avec cet indicateur défini, une requête effectuée lorsque le focus est verrouillé
renvoie AUDIOFOCUS_REQUEST_DELAYED
. Lorsque la condition qui a verrouillé l'audio
n'existe plus. Par exemple, à la fin d'un appel téléphonique, le système
accorde la demande de sélection en attente et appelle onAudioFocusChange()
pour avertir votre
l'application.
Afin de gérer le gain de focus retardé, vous devez créer un
OnAudioFocusChangeListener
avec une méthode de rappel onAudioFocusChange()
qui
implémente le comportement souhaité et enregistre l'écouteur en appelant
setOnAudioFocusChangeListener()
Priorité audio sur Android 7.1 ou version antérieure
Lorsque vous appelez
requestAudioFocus()
vous devez spécifier une durée
être mis à l'honneur par une autre application actuellement sélectionnée et en cours de lecture:
- Demander la priorité audio permanente (
AUDIOFOCUS_GAIN
) lorsque vous prévoyez de lire du contenu audio dans un futur proche (par exemple, lorsque vous écoutez de la musique). conteneur précédent de la sélection audio pour arrêter la lecture. - Demander le focus temporaire (
AUDIOFOCUS_GAIN_TRANSIENT
) lorsque vous prévoyez de jouer le contenu audio d'un court laps de temps, lorsque vous pensez que l'élément précédent doit être mis en pause ; en cours de lecture. - Demander un focus temporaire avec diminution
(
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
) pour indiquer que vous comptez lire du contenu audio que pendant une courte période et qu'il peut conserver CANNOT TRANSLATE (baisse) sa sortie audio. Les deux sorties audio sont mixtes dans le flux audio. La diminution est particulièrement adaptée aux applications qui utilisent flux audio par intermittence, par exemple pour les itinéraires routiers audibles.
La méthode requestAudioFocus()
nécessite également un AudioManager.OnAudioFocusChangeListener
. Cet écouteur doit être
dans l'activité ou le service propriétaire de votre session multimédia. Il
implémente le rappel onAudioFocusChange()
que votre application reçoit lorsque
une autre application acquiert ou abandonne la priorité audio.
L'extrait suivant demande la priorité audio permanente sur le flux
STREAM_MUSIC
et enregistre un OnAudioFocusChangeListener
à gérer
modifications ultérieures de la priorité audio. (L'écouteur de changement est abordé dans
Répondre à un changement de priorité audio)
Kotlin
audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager lateinit var afChangeListener AudioManager.OnAudioFocusChangeListener ... // Request audio focus for playback val result: Int = audioManager.requestAudioFocus( afChangeListener, // Use the music stream. AudioManager.STREAM_MUSIC, // Request permanent focus. AudioManager.AUDIOFOCUS_GAIN ) if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { // Start playback }
Java
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); AudioManager.OnAudioFocusChangeListener afChangeListener; ... // Request audio focus for playback int result = audioManager.requestAudioFocus(afChangeListener, // Use the music stream. AudioManager.STREAM_MUSIC, // Request permanent focus. AudioManager.AUDIOFOCUS_GAIN); if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { // Start playback }
Une fois la lecture terminée, appelez
abandonAudioFocus()
Kotlin
audioManager.abandonAudioFocus(afChangeListener)
Java
// Abandon audio focus when playback complete audioManager.abandonAudioFocus(afChangeListener);
Cela indique au système que vous n'avez plus besoin du ciblage et annule l'enregistrement du
OnAudioFocusChangeListener
associé. Si vous avez demandé une mise au point temporaire,
cela informera une appli qui s'est arrêtée ou baissée qu'elle peut continuer à lire ou
rétablir le volume.
Répondre à un changement de priorité audio
Lorsqu'une application acquiert la priorité audio, elle doit pouvoir la publier lorsqu'une autre application
demande la priorité audio pour elle-même. Dans ce cas, votre application
reçoit un appel vers
onAudioFocusChange()
dans AudioFocusChangeListener
que vous avez spécifié lorsque l'application a appelé requestAudioFocus()
.
Le paramètre focusChange
transmis à onAudioFocusChange()
indique le genre
du changement en cours. Elle correspond
par rapport à l'indicateur de durée utilisé
par l'application qui acquiert l'attention. Votre application doit
répondre de manière appropriée.
- Perte de concentration temporaire
-
Si le changement d'objectif est temporaire (
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
ouAUDIOFOCUS_LOSS_TRANSIENT
), votre application devrait baisser (si vous ne comptez pas en cas d'atténuation automatique) ou mettre la lecture en pause, mais sinon ils conservent le même état.En cas de perte temporaire de la priorité audio, vous devez continuer à surveiller les changements et soyez prêt à reprendre la lecture normale dès que le son le focus. Lorsque l'application bloquante abandonne le focus, vous recevez un rappel (
AUDIOFOCUS_GAIN
). À ce stade, vous pouvez rétablir le volume normal ou relancer la lecture. - Perte de concentration permanente
-
Si la perte de la sélection audio est permanente (
AUDIOFOCUS_LOSS
), une autre application est de la lecture du contenu audio. Votre application doit mettre la lecture immédiatement en pause, car elle n'effectuera jamais recevoir un rappelAUDIOFOCUS_GAIN
. Pour relancer la lecture, l'utilisateur doit effectuer une action explicite, comme appuyer sur la commande de lecture de transport dans une notification ou dans l'UI d'une application.
L'extrait de code suivant montre comment mettre en œuvre
OnAudioFocusChangeListener
et son rappel onAudioFocusChange()
. Notez que
Utilisation d'un Handler
pour retarder le rappel d'arrêt en cas de perte définitive de l'audio
le focus.
Kotlin
private val handler = Handler() private val afChangeListener = AudioManager.OnAudioFocusChangeListener { focusChange -> when (focusChange) { AudioManager.AUDIOFOCUS_LOSS -> { // Permanent loss of audio focus // Pause playback immediately mediaController.transportControls.pause() // Wait 30 seconds before stopping playback handler.postDelayed(delayedStopRunnable, TimeUnit.SECONDS.toMillis(30)) } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { // Pause playback } AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { // Lower the volume, keep playing } AudioManager.AUDIOFOCUS_GAIN -> { // Your app has been granted audio focus again // Raise volume to normal, restart playback if necessary } } }
Java
private Handler handler = new Handler(); AudioManager.OnAudioFocusChangeListener afChangeListener = new AudioManager.OnAudioFocusChangeListener() { public void onAudioFocusChange(int focusChange) { if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { // Permanent loss of audio focus // Pause playback immediately mediaController.getTransportControls().pause(); // Wait 30 seconds before stopping playback handler.postDelayed(delayedStopRunnable, TimeUnit.SECONDS.toMillis(30)); } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) { // Pause playback } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { // Lower the volume, keep playing } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { // Your app has been granted audio focus again // Raise volume to normal, restart playback if necessary } } };
Le gestionnaire utilise un Runnable
qui se présente comme suit:
Kotlin
private var delayedStopRunnable = Runnable { mediaController.transportControls.stop() }
Java
private Runnable delayedStopRunnable = new Runnable() { @Override public void run() { getMediaController().getTransportControls().stop(); } };
Pour vous assurer que l'arrêt différé ne se déclenche pas si l'utilisateur relance la lecture, appelez
mHandler.removeCallbacks(mDelayedStopRunnable)
en réponse à n'importe quel état
des modifications. Par exemple, appelez removeCallbacks()
dans le onPlay()
de votre rappel :
onSkipToNext()
, etc. Vous devez également appeler cette méthode dans l'objet
Rappel onDestroy()
lors du nettoyage des ressources utilisées par votre service.