L'Assistant Google vous permet d'utiliser des commandes vocales pour contrôler de nombreux appareils, comme Google Home, votre téléphone et plus encore. Il intègre une fonctionnalité permettant de comprendre les commandes multimédias ("mets un titre de Beyoncé") et est compatible avec les commandes multimédias (comme mettre en pause, passer, avancer, J'aime).
L'Assistant communique avec les applications multimédias Android à l'aide d'une session multimédia. Il peut utiliser des intents ou des services pour lancer votre application et démarrer la lecture. Pour obtenir les meilleurs résultats, votre application doit implémenter toutes les fonctionnalités décrites sur cette page.
Utiliser une session multimédia
Chaque application audio et vidéo doit implémenter une session multimédia afin que l'Assistant puisse utiliser les commandes de transport une fois la lecture lancée.
Notez que, bien que l'Assistant n'utilise que les actions listées dans cette section, il est recommandé d'implémenter toutes les API de préparation et de lecture pour assurer la compatibilité avec d'autres applications. Pour toute action que vous ne prenez pas en charge, les rappels de session multimédia peuvent simplement renvoyer une erreur à l'aide de ERROR_CODE_NOT_SUPPORTED.
Activez les commandes multimédias et de transport en définissant ces indicateurs dans l'objet MediaSession de votre application :
Kotlin
session.setFlags( MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS )
Java
session.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
La session multimédia de votre application doit déclarer les actions qu'elle prend en charge et implémenter les rappels de session multimédia correspondants. Déclarez les actions acceptées dans setActions().
L'exemple de projet Universal Android Music Player est un bon exemple de configuration d'une session multimédia.
Actions de lecture
Pour démarrer la lecture à partir d'un service, une session multimédia doit comporter les actions PLAY et leurs rappels suivants :
| Action | Rappel |
|---|---|
ACTION_PLAY |
onPlay() |
ACTION_PLAY_FROM_SEARCH |
onPlayFromSearch() |
ACTION_PLAY_FROM_URI (*) |
onPlayFromUri() |
Votre session doit également implémenter les actions PREPARE et leurs rappels suivants :
| Action | Rappel |
|---|---|
ACTION_PREPARE |
onPrepare() |
ACTION_PREPARE_FROM_SEARCH |
onPrepareFromSearch() |
ACTION_PREPARE_FROM_URI (*) |
onPrepareFromUri() |
(*) Les actions basées sur les URI de l'Assistant Google ne fonctionnent que pour les entreprises qui fournissent des URI à Google. Pour en savoir plus sur la description de vos contenus multimédias à Google, consultez Actions multimédias.
En implémentant les API de préparation, la latence de lecture après une commande vocale peut être réduite. Les applications multimédias qui souhaitent améliorer la latence de lecture peuvent utiliser ce temps supplémentaire pour commencer à mettre en cache le contenu et à préparer la lecture du contenu multimédia.
Analyser les requêtes de recherche
Lorsqu'un utilisateur recherche un élément multimédia spécifique, comme "Écoute du jazz sur [nom de votre application]" ou "Écoute [titre de la chanson]", la méthode de rappel onPrepareFromSearch() ou onPlayFromSearch() reçoit un paramètre de requête et un bundle d'extras.
Votre application doit analyser la requête de recherche vocale et lancer la lecture en suivant ces étapes :
- Utilisez le bundle d'extras et la chaîne de requête de recherche renvoyés par la recherche vocale pour filtrer les résultats.
- Créez une file de lecture à partir de ces résultats.
- lire l'élément multimédia le plus pertinent parmi les résultats ;
La méthode onPlayFromSearch() accepte un paramètre "extras" contenant des informations plus détaillées sur la recherche vocale. Ces extras vous aident à trouver le contenu audio dans votre application pour la lecture.
Si les résultats de recherche ne peuvent pas fournir ces données, vous pouvez implémenter une logique pour analyser la requête de recherche brute et lire les pistes appropriées en fonction de la requête.
Les extras suivants sont compatibles avec Android Automotive OS et Android Auto :
L'extrait de code suivant montre comment remplacer la méthode onPlayFromSearch() dans votre implémentation MediaSession.Callback pour analyser la requête de recherche vocale et lancer la lecture :
Kotlin
override fun onPlayFromSearch(query: String?, extras: Bundle?) { if (query.isNullOrEmpty()) { // The user provided generic string e.g. 'Play music' // Build appropriate playlist queue } else { // Build a queue based on songs that match "query" or "extras" param val mediaFocus: String? = extras?.getString(MediaStore.EXTRA_MEDIA_FOCUS) if (mediaFocus == MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE) { isArtistFocus = true artist = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST) } else if (mediaFocus == MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE) { isAlbumFocus = true album = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM) } // Implement additional "extras" param filtering } // Implement your logic to retrieve the queue var result: String? = when { isArtistFocus -> artist?.also { searchMusicByArtist(it) } isAlbumFocus -> album?.also { searchMusicByAlbum(it) } else -> null } result = result ?: run { // No focus found, search by query for song title query?.also { searchMusicBySongTitle(it) } } if (result?.isNotEmpty() == true) { // Immediately start playing from the beginning of the search results // Implement your logic to start playing music playMusic(result) } else { // Handle no queue found. Stop playing if the app // is currently playing a song } }
Java
@Override public void onPlayFromSearch(String query, Bundle extras) { if (TextUtils.isEmpty(query)) { // The user provided generic string e.g. 'Play music' // Build appropriate playlist queue } else { // Build a queue based on songs that match "query" or "extras" param String mediaFocus = extras.getString(MediaStore.EXTRA_MEDIA_FOCUS); if (TextUtils.equals(mediaFocus, MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE)) { isArtistFocus = true; artist = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST); } else if (TextUtils.equals(mediaFocus, MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE)) { isAlbumFocus = true; album = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM); } // Implement additional "extras" param filtering } // Implement your logic to retrieve the queue if (isArtistFocus) { result = searchMusicByArtist(artist); } else if (isAlbumFocus) { result = searchMusicByAlbum(album); } if (result == null) { // No focus found, search by query for song title result = searchMusicBySongTitle(query); } if (result != null && !result.isEmpty()) { // Immediately start playing from the beginning of the search results // Implement your logic to start playing music playMusic(result); } else { // Handle no queue found. Stop playing if the app // is currently playing a song } }
Pour obtenir un exemple plus détaillé de l'implémentation de la recherche vocale pour lire du contenu audio dans votre application, consultez l'exemple Universal Android Music Player.
Gérer les requêtes vides
Si onPrepare(), onPlay(), onPrepareFromSearch() ou onPlayFromSearch() sont appelés sans requête de recherche, votre application multimédia doit lire le contenu multimédia "actuel". S'il n'y a pas de contenu multimédia en cours de lecture, l'application doit essayer d'en lire un, par exemple un titre de la playlist la plus récente ou une file d'attente aléatoire. L'Assistant utilise ces API lorsqu'un utilisateur demande à lire de la musique sur [nom de votre application] sans informations supplémentaires.
Lorsqu'un utilisateur dit "Lire de la musique sur [nom de votre application]", Android Automotive OS ou Android Auto tente de lancer votre application et de lire l'audio en appelant la méthode onPlayFromSearch() de votre application. Toutefois, comme l'utilisateur n'a pas indiqué le nom de l'élément multimédia, la méthode onPlayFromSearch() reçoit un paramètre de requête vide. Dans ce cas, votre application doit répondre en lisant immédiatement un contenu audio, comme un titre de la playlist la plus récente ou une file d'attente aléatoire.
Déclarer la prise en charge des anciennes commandes vocales
Dans la plupart des cas, la gestion des actions de lecture décrites ci-dessus fournit à votre application toutes les fonctionnalités de lecture dont elle a besoin. Cependant, certains systèmes exigent que votre application contienne un filtre d'intent pour la recherche. Vous devez déclarer la prise en charge de ce filtre d'intent dans les fichiers manifestes de votre application.
Ajoutez ce code dans le fichier manifeste d'une application pour téléphone :
<activity>
<intent-filter>
<action android:name=
"android.media.action.MEDIA_PLAY_FROM_SEARCH" />
<category android:name=
"android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Commandes de transport
Une fois la session multimédia de votre application active, l'Assistant peut émettre des commandes vocales pour contrôler la lecture et mettre à jour les métadonnées multimédias. Pour que cela fonctionne, votre code doit permettre les actions suivantes et implémenter les rappels correspondants :
| Action | Rappel | Description |
|---|---|---|
ACTION_SKIP_TO_NEXT |
onSkipToNext() |
Vidéo suivante |
ACTION_SKIP_TO_PREVIOUS |
onSkipToPrevious() |
Titre précédent |
ACTION_PAUSE, ACTION_PLAY_PAUSE |
onPause() |
Pause |
ACTION_STOP |
onStop() |
Arrêter |
ACTION_PLAY |
onPlay() |
Reprendre |
ACTION_SEEK_TO |
onSeekTo() |
Revenir en arrière de 30 secondes |
ACTION_SET_RATING |
onSetRating(android.support.v4.media.RatingCompat) |
Pouce vers le haut/bas. |
ACTION_SET_CAPTIONING_ENABLED |
onSetCaptioningEnabled(boolean) |
Activez ou désactivez les sous-titres. |
Remarque :
- Pour que les commandes de recherche fonctionnent,
PlaybackStatedoit être à jour avecstate, position, playback speed, and update time. L'application doit appelersetPlaybackState()lorsque l'état change. - L'application multimédia doit également tenir à jour les métadonnées de la session multimédia. Vous pouvez ainsi poser des questions comme "Quelle est cette chanson ?". L'application doit appeler
setMetadata()lorsque les champs applicables (tels que le titre, l'artiste et le nom du titre) changent. MediaSession.setRatingType()doit être défini pour indiquer le type de classification pris en charge par l'application, et l'application doit implémenteronSetRating(). Si l'application n'est pas compatible avec les notes, elle doit définir le type de note surRATING_NONE.
Les actions vocales que vous acceptez varient probablement en fonction du type de contenu.
| Type de contenu | Actions requises |
|---|---|
| Musique |
Doit être compatible avec : lecture, pause, arrêt, passer au titre suivant et passer au titre précédent Prise en charge fortement recommandée : Seek To |
| Podcast |
Doit être compatible avec : Lecture, Pause, Arrêt et Aller à Recommandations d'assistance pour : Passer à la piste suivante et Passer à la piste précédente |
| Livre audio | Doit être compatible avec : Lecture, Pause, Arrêt et Aller à |
| Radio | Doit être compatible avec : Lecture, Pause et Arrêt |
| Actualités | Doit être compatible avec : lecture, pause, arrêt, passer au titre suivant et passer au titre précédent |
| Vidéo |
Doit être compatible avec : lecture, pause, arrêt, recherche, retour arrière et avance rapide Prise en charge fortement recommandée : Passer à la piste suivante et Passer à la piste précédente |
Vous devez prendre en charge autant d'actions listées ci-dessus que vos offres de produits le permettent, tout en répondant de manière appropriée à toute autre action. Par exemple, si seuls les utilisateurs Premium peuvent revenir à l'élément précédent, vous pouvez générer une erreur si un utilisateur du forfait sans frais demande à l'Assistant de revenir à l'élément précédent. Pour obtenir plus d'informations, consultez la section sur la gestion des erreurs.
Exemples de requêtes vocales à essayer
Le tableau suivant présente quelques exemples de requêtes que vous devez utiliser pour tester votre implémentation :
| Rappel MediaSession | Phrase "Hey Google" à utiliser | |
|---|---|---|
onPlay() |
"Jouer." "Reprends la lecture." |
|
onPlayFromSearch()
onPlayFromUri() |
Musique |
"Mets de la musique ou des titres sur (nom de l'application)." Il s'agit d'une requête vide. "Mets (chanson | artiste | album | genre | playlist) sur (nom de l'application)." |
| Radio | "Mets (fréquence | station) sur (nom de l'application)." | |
| Audiobook |
"Lis mon livre audio sur (nom de l'application)." "Lis (livre audio) sur (nom de l'application)." |
|
| Podcasts | "Mets (podcast) sur (nom de l'application)." | |
onPause() |
"Mets en pause." | |
onStop() |
"Arrête." | |
onSkipToNext() |
"Suivant (titre | épisode | piste)" | |
onSkipToPrevious() |
"Précédent (titre | épisode | piste)" | |
onSeekTo() |
"Redémarre." "Avance de ## secondes." "Reviens en arrière de ## minutes." |
|
N/A (maintenez votre
MediaMetadata
à jour) |
"Qu'est-ce qui passe actuellement ?" | |
Erreurs
L'Assistant gère les erreurs d'une session multimédia lorsqu'elles se produisent et les signale aux utilisateurs. Assurez-vous que votre session multimédia met à jour correctement l'état du transport et le code d'erreur dans son PlaybackState, comme décrit dans Utiliser une session multimédia. L'Assistant reconnaît tous les codes d'erreur renvoyés par getErrorCode().
Cas souvent mal gérés
Voici quelques exemples de cas d'erreur que vous devez gérer correctement :
- L'utilisateur doit se connecter
- Définissez le code d'erreur
PlaybackStatesurERROR_CODE_AUTHENTICATION_EXPIRED. - Définissez le message d'erreur
PlaybackState. - Si l'état
PlaybackStateest nécessaire pour la lecture, définissez-le surSTATE_ERROR. Sinon, conservez le reste de l'étatPlaybackStatetel quel.
- Définissez le code d'erreur
- L'utilisateur demande une action non disponible.
- Définissez le code d'erreur
PlaybackStatede manière appropriée. Par exemple, définissezPlaybackStatesurERROR_CODE_NOT_SUPPORTEDsi l'action n'est pas prise en charge ou surERROR_CODE_PREMIUM_ACCOUNT_REQUIREDsi l'action est protégée par une connexion. - Définissez le message d'erreur
PlaybackState. - Conservez le reste de
PlaybackStatetel quel.
- Définissez le code d'erreur
- L'utilisateur demande du contenu non disponible dans l'application
- Définissez le code d'erreur
PlaybackStatede manière appropriée. Par exemple, utilisezERROR_CODE_NOT_AVAILABLE_IN_REGION. - Définissez le message d'erreur
PlaybackState. - Définissez l'état
PlaybackSatesurSTATE_ERRORpour interrompre la lecture, sinon conservez le reste dePlaybackStatetel quel.
- Définissez le code d'erreur
- L'utilisateur demande du contenu pour lequel aucune correspondance exacte n'est disponible. Par exemple, un utilisateur du forfait sans frais demande du contenu réservé aux utilisateurs du forfait Premium.
- Nous vous recommandons de ne pas renvoyer d'erreur, mais plutôt de trouver un contenu similaire à lire. L'Assistant se chargera de prononcer la réponse vocale la plus pertinente avant le début de la lecture.
Lecture avec un intent
L'Assistant peut lancer une application audio ou vidéo et démarrer la lecture en envoyant un intent avec un lien profond.
L'intention et son lien profond peuvent provenir de différentes sources :
- Lorsque l'Assistant démarre une application mobile, il peut utiliser la recherche Google pour récupérer du contenu balisé qui fournit une action de visionnage avec un lien.
- Lorsque l'Assistant démarre une application TV, votre application doit inclure un fournisseur de recherche TV pour exposer les URI des contenus multimédias. L'Assistant envoie une requête au fournisseur de contenu, qui doit renvoyer un intent contenant un URI pour le lien profond et une action facultative.
Si la requête renvoie une action dans l'intent, l'Assistant renvoie cette action et l'URI à votre application. Si le fournisseur n'a pas spécifié d'action, l'Assistant ajoutera
ACTION_VIEWà l'intent.
L'Assistant ajoute l'extra EXTRA_START_PLAYBACK avec la valeur true à l'intention qu'il envoie à votre application. Votre application doit lancer la lecture lorsqu'elle reçoit une intention avec EXTRA_START_PLAYBACK.
Gérer les intents en mode actif
Les utilisateurs peuvent demander à l'Assistant de lire un contenu alors que votre application est en train de lire un contenu provenant d'une requête précédente. Cela signifie que votre application peut recevoir de nouveaux intents pour démarrer la lecture alors que son activité de lecture est déjà lancée et active.
Les activités qui acceptent les intents avec des liens profonds doivent remplacer onNewIntent() pour gérer les nouvelles requêtes.
Lorsque la lecture commence, l'Assistant peut ajouter des indicateurs supplémentaires à l'intention qu'il envoie à votre application. Il peut notamment ajouter FLAG_ACTIVITY_CLEAR_TOP ou FLAG_ACTIVITY_NEW_TASK, ou les deux. Bien que votre code n'ait pas besoin de gérer ces indicateurs, le système Android y répond.
Cela peut affecter le comportement de votre application lorsqu'une deuxième demande de lecture avec un nouvel URI arrive alors que l'URI précédent est toujours en cours de lecture. Il est recommandé de tester la réaction de votre application dans ce cas. Vous pouvez utiliser l'outil de ligne de commande adb pour simuler la situation (la constante 0x14000000 est le OU bit à bit booléen des deux indicateurs) :
adb shell 'am start -a android.intent.action.VIEW --ez android.intent.extra.START_PLAYBACK true -d "<first_uri>"' -f 0x14000000
adb shell 'am start -a android.intent.action.VIEW --ez android.intent.extra.START_PLAYBACK true -d "<second_uri>"' -f 0x14000000
Lecture à partir d'un service
Si votre application possède un media browser service qui autorise les connexions depuis l'Assistant, celui-ci peut démarrer l'application en communiquant avec le media session du service.
Le service de navigateur multimédia ne doit jamais lancer d'activité.
L'Assistant lancera votre activité en fonction de la PendingIntent que vous définissez avec setSessionActivity().
Veillez à définir MediaSession.Token lorsque vous initialisez le service de navigateur multimédia. N'oubliez pas de définir les actions de lecture compatibles à tout moment, y compris lors de l'initialisation. L'Assistant s'attend à ce que votre application multimédia définisse les actions de lecture avant qu'il n'envoie la première commande de lecture.
Pour démarrer à partir d'un service, l'Assistant implémente les API clientes du navigateur multimédia. Elle effectue des appels TransportControls qui déclenchent des rappels d'action PLAY sur la session multimédia de votre application.
Le diagramme suivant montre l'ordre des appels générés par l'Assistant et les rappels de session multimédia correspondants. (Les rappels de préparation ne sont envoyés que si votre application les prend en charge.) Tous les appels sont asynchrones. L'Assistant n'attend aucune réponse de votre application.

Lorsqu'un utilisateur émet une commande vocale pour lancer la lecture, l'Assistant répond par une brève annonce. Dès que l'annonce est terminée, l'Assistant émet une action PLAY. Elle n'attend aucun état de lecture spécifique.
Si votre application est compatible avec les actions ACTION_PREPARE_*, l'Assistant appelle l'action PREPARE avant de commencer l'annonce.
Se connecter à un MediaBrowserService
Pour utiliser un service afin de démarrer votre application, l'Assistant doit pouvoir se connecter au MediaBrowserService de l'application et récupérer son MediaSession.Token. Les demandes de connexion sont traitées dans la méthode onGetRoot() du service. Il existe deux façons de traiter les demandes :
- Accepter toutes les demandes de connexion
- Accepter les demandes de connexion uniquement depuis l'application Assistant
Accepter toutes les demandes de connexion
Vous devez renvoyer un BrowserRoot pour permettre à l'Assistant d'envoyer des commandes à votre session multimédia. La méthode la plus simple consiste à autoriser toutes les applications MediaBrowser à se connecter à votre MediaBrowserService. Vous devez renvoyer un BrowserRoot non nul. Voici le code applicable de Universal Music Player :
Kotlin
override fun onGetRoot( clientPackageName: String, clientUid: Int, rootHints: Bundle? ): BrowserRoot? { // To ensure you are not allowing any arbitrary app to browse your app's contents, you // need to check the origin: if (!packageValidator.isCallerAllowed(this, clientPackageName, clientUid)) { // If the request comes from an untrusted package, return an empty browser root. // If you return null, then the media browser will not be able to connect and // no further calls will be made to other media browsing methods. Log.i(TAG, "OnGetRoot: Browsing NOT ALLOWED for unknown caller. Returning empty " + "browser root so all apps can use MediaController. $clientPackageName") return MediaBrowserServiceCompat.BrowserRoot(MEDIA_ID_EMPTY_ROOT, null) } // Return browser roots for browsing... }
Java
@Override public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, Bundle rootHints) { // To ensure you are not allowing any arbitrary app to browse your app's contents, you // need to check the origin: if (!packageValidator.isCallerAllowed(this, clientPackageName, clientUid)) { // If the request comes from an untrusted package, return an empty browser root. // If you return null, then the media browser will not be able to connect and // no further calls will be made to other media browsing methods. LogHelper.i(TAG, "OnGetRoot: Browsing NOT ALLOWED for unknown caller. " + "Returning empty browser root so all apps can use MediaController." + clientPackageName); return new MediaBrowserServiceCompat.BrowserRoot(MEDIA_ID_EMPTY_ROOT, null); } // Return browser roots for browsing... }
Accepter le package et la signature de l'application Assistant
Vous pouvez autoriser explicitement l'Assistant à se connecter à votre service de navigateur multimédia en vérifiant son nom de package et sa signature. Votre application recevra le nom du package dans la méthode onGetRoot de votre MediaBrowserService. Vous devez renvoyer un BrowserRoot pour permettre à l'Assistant d'envoyer des commandes à votre session multimédia. L'exemple Universal Music Player gère une liste de noms de packages et de signatures connus. Vous trouverez ci-dessous les noms de package et les signatures utilisés par l'Assistant Google.
<signature name="Google" package="com.google.android.googlequicksearchbox">
<key release="false">19:75:b2:f1:71:77:bc:89:a5:df:f3:1f:9e:64:a6:ca:e2:81:a5:3d:c1:d1:d5:9b:1d:14:7f:e1:c8:2a:fa:00</key>
<key release="true">f0:fd:6c:5b:41:0f:25:cb:25:c3:b5:33:46:c8:97:2f:ae:30:f8:ee:74:11:df:91:04:80:ad:6b:2d:60:db:83</key>
</signature>
<signature name="Google Assistant on Android Automotive OS" package="com.google.android.carassistant">
<key release="false">17:E2:81:11:06:2F:97:A8:60:79:7A:83:70:5B:F8:2C:7C:C0:29:35:56:6D:46:22:BC:4E:CF:EE:1B:EB:F8:15</key>
<key release="true">74:B6:FB:F7:10:E8:D9:0D:44:D3:40:12:58:89:B4:23:06:A6:2C:43:79:D0:E5:A6:62:20:E3:A6:8A:BF:90:E2</key>
</signature>