Assistant Google et applications multimédias

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 dispose d'une fonctionnalité intégrée comprendre les commandes multimédias ("joue quelque chose de Beyoncé") et prend en charge les commandes multimédias (pause, saut, avance rapide, pouce levé, etc.) ;

L'Assistant communique avec les applications multimédias Android à l'aide d'un contenu multimédia session. Elle peut utiliser des intents ou des services pour lancer votre application et lancer la lecture. Pour des résultats optimaux, votre application doit : mettre en œuvre toutes les fonctionnalités décrites sur cette page.

Utiliser une session multimédia

Chaque application audio et vidéo doit implémenter un session multimédia pour que l'Assistant puisse fonctionner les commandes de transport une fois la lecture lancée.

Notez que même si l'Assistant n'utilise que les actions indiquées dans cette section, les il est recommandé d'implémenter toutes les API de préparation et de lecture pour garantir la compatibilité avec d'autres applications. Pour toutes les actions que vous n'acceptez pas, les rappels de session multimédia peuvent simplement renvoyer une erreur en utilisant ERROR_CODE_NOT_SUPPORTED

Activez les commandes multimédias et de transport en définissant ces indicateurs dans le menu Objet MediaSession:

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 compatibles et implémenter la les rappels de session multimédia correspondants. Déclarez vos actions acceptées dans setActions()

La Lecteur de musique universel Android exemple de projet est un bon exemple de la façon d'organiser une session multimédia.

Actions de lecture

Pour lancer la lecture à partir d'un service, une session multimédia doit comporter les actions PLAY suivantes et leurs rappels:

Action Rappel
ACTION_PLAY onPlay()
ACTION_PLAY_FROM_SEARCH onPlayFromSearch()
ACTION_PLAY_FROM_URI (*) onPlayFromUri()

Votre session doit également implémenter ces actions PREPARE et leurs rappels:

Action Rappel
ACTION_PREPARE onPrepare()
ACTION_PREPARE_FROM_SEARCH onPrepareFromSearch()
ACTION_PREPARE_FROM_URI (*) onPrepareFromUri()

(*) Les actions basées sur l'URI de l'Assistant Google ne fonctionnent que pour les entreprises qui fournissent des URI à Google. Pour en savoir plus sur la description de votre contenu multimédia à Google consultez la section Media Actions (Actions multimédias).

Grâce à la mise en œuvre des API de préparation, la latence de lecture après une commande vocale peut être réduit. Les applications multimédias qui souhaitent améliorer la latence de lecture peuvent utiliser plus de temps pour commencer la mise en cache du contenu et la préparation de la lecture du contenu multimédia.

Analyser les requêtes de recherche

Lorsqu'un utilisateur recherche un élément multimédia spécifique, par exemple "Mets du jazz sur [nom de votre application]" ou "Écouter [titre de la chanson]", le 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:

  1. Utiliser le bundle d'extras et la chaîne de requête de recherche renvoyés par la recherche vocale pour filtrer les résultats.
  2. Créez une file d'attente de lecture en fonction de ces résultats.
  3. Lire l'élément multimédia le plus pertinent parmi les résultats.

onPlayFromSearch() utilise un paramètre extras avec des informations plus détaillées provenant de la voix. recherche. Ces extras vous aident à trouver le contenu audio dans votre application pour la lecture. Si les résultats de recherche ne sont pas en mesure de fournir ces données, vous pouvez implémenter une logique pour analyser la requête de recherche brute et lire les titres appropriés en fonction requête.

Les extras suivants sont compatibles avec Android Automotive OS et Android Auto:

L'extrait de code suivant montre comment remplacer onPlayFromSearch() dans votre 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é d'implémentation de la recherche vocale pour lire du contenu audio contenu dans votre application, consultez la page consacrée au lecteur de musique Universal Android. échantillon.

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 la chaîne "actuelle" médias. Si aucun contenu multimédia n'est actuellement disponible, l'application doit essayer de lire un contenu, par exemple comme un titre de la playlist la plus récente ou d'une file d'attente aléatoire. L'assistant utilise ces API lorsqu'un utilisateur demande à mettre de la musique sur [nom de votre application] sans plus d'informations.

Lorsqu'un utilisateur dit Mets de la musique sur [nom de votre application], Android Automotive OS ou Android Auto tente de lancer votre application et de lire du contenu audio en appelant la méthode onPlayFromSearch() de votre application . Toutefois, comme l'utilisateur n'a pas dit le nom de l'élément multimédia, onPlayFromSearch() reçoit un paramètre de requête vide. Dans ce cas, votre application doit réagissent en diffusant immédiatement un contenu audio, comme un titre de l'un des derniers ou dans une file d'attente aléatoire.

Déclarer une ancienne compatibilité des commandes vocales

Dans la plupart des cas, la gestion des actions de lecture décrites ci-dessus permet à votre application la fonctionnalité de lecture dont elle a besoin. Cependant, certains systèmes exigent que votre application contiennent un filtre d'intent pour la recherche. Vous devez déclarer la prise en charge de cet intent dans les fichiers manifestes de votre application.

Incluez 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

Lorsque la session multimédia de votre appli est active, l'Assistant peut émettre des commandes vocales pour contrôler la lecture et mettre à jour les métadonnées des contenus multimédias. Pour que cela fonctionne, doit permettre les actions suivantes et implémenter Rappels:

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() Mettre en 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) J'aime/Je n'aime pas.
ACTION_SET_CAPTIONING_ENABLED onSetCaptioningEnabled(boolean) activer ou désactiver les sous-titres ;

Remarque :

  • Pour que les commandes de recherche fonctionnent, PlaybackState doit être à jour avec state, position, playback speed, and update time. L'application doit appeler setPlaybackState() lorsque l'état change.
  • L'application multimédia doit également maintenir les métadonnées de la session multimédia à jour. Cela permet de répondre à des questions telles que "Quel est le titre en cours de lecture ?". L'application doit appeler setMetadata() lorsque les champs applicables (comme le titre, l'artiste et le nom du morceau) changent.
  • MediaSession.setRatingType() doit être défini pour indiquer le type de classification accepté par l'application, et l'application doit implémenter onSetRating(). Si l'application n'est pas compatible avec la classification, le type de classification doit être RATING_NONE.

Les commandes vocales que vous acceptez peuvent varier en fonction du type de contenu.

Type de contenu Actions requises
Musique

Fonctionnalités obligatoires: Lecture, Pause, Arrêt, Passer à l'élément suivant et Passer à l'élément précédent

Recommander fortement l'assistance pour: Aller à

Podcast

Doit être compatible: Lire, Mettre en pause, Arrêter et Aller à

Recommander la prise en charge de: Passer à "Suivant" et "Précédent"

Livre audio Doit être compatible: Lire, Mettre en pause, Arrêter et Aller à
Radio Doit être compatible: Lecture, Pause et Arrêt
Actualités Fonctionnalités obligatoires: Lecture, Pause, Arrêt, Passer à l'élément suivant et Passer à l'élément précédent
Vidéo

Fonctionnalités obligatoires: lecture, mise en pause, arrêt, fonctionnalité de recherche, retour en arrière et avance rapide

Recommander fortement l'assistance pour: Passer à l'élément suivant et Passer à l'élément précédent

Vous devez accepter autant d'actions listées ci-dessus que vos offres de produits. autoriser, mais toujours de répondre convivialement à toute autre action. Par exemple, si seulement les utilisateurs premium ont la possibilité de revenir à l'élément précédent, vous pouvez augmenter une erreur si un utilisateur du niveau sans frais demande à l'Assistant de revenir à l'élément précédent. Pour en savoir plus, consultez la section Gestion des erreurs.

Exemples de requêtes vocales à essayer

Le tableau suivant présente quelques exemples de requêtes à utiliser pour testez votre implémentation:

Rappel MediaSession l'expression "Hey Google" à utiliser
onPlay()

"Lance la lecture."

"Reprends la lecture".

onPlayFromSearch()
onPlayFromUri()
Musique

"Joue de la musique ou des titres sur (nom de l'application)." Cette requête est vide.

"Mets (titre | 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 "Lis (podcast) sur (nom de l'application)."
onPause() "Mets sur pause."
onStop() "Arrête la lecture."
onSkipToNext() "Next (titre | épisode | titre)."
onSkipToPrevious() "Précédent (titre | épisode | titre)."
onSeekTo()

"Reprends la lecture."

"Avance de ## secondes."

"Reviens en arrière de ## minutes."

N/A (Gardez votre MediaMetadata mis à jour) "Qu'est-ce qui passe actuellement ?"

Erreurs

L'Assistant traite les erreurs d'une session multimédia lorsqu'elles se produisent et signale aux utilisateurs. Assurez-vous que votre session multimédia met à jour l'état de transport et code d'erreur dans son PlaybackState, comme décrit dans la section Utiliser un session multimédia. Assistant reconnaît tous les codes d'erreur renvoyés par getErrorCode()

Cas fréquemment mal gérés

Voici quelques exemples de cas d'erreur à gérer correctement:

  • L'utilisateur doit se connecter <ph type="x-smartling-placeholder">
      </ph>
    • Définissez le code d'erreur PlaybackState sur ERROR_CODE_AUTHENTICATION_EXPIRED.
    • Définissez le message d'erreur PlaybackState.
    • Si nécessaire pour la lecture, définissez l'état PlaybackState sur STATE_ERROR. Sinon, conservez le reste de PlaybackState tel quel.
  • L'utilisateur demande une action non disponible <ph type="x-smartling-placeholder">
      </ph>
    • Définissez le code d'erreur PlaybackState de manière appropriée. Par exemple, définissez le paramètre PlaybackState à ERROR_CODE_NOT_SUPPORTED si l'action n'est pas acceptée ou ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED si l'action est protégée par une procédure de connexion.
    • Définissez le message d'erreur PlaybackState.
    • Conservez le reste de PlaybackState tel quel.
  • L'utilisateur demande un contenu non disponible dans l'application <ph type="x-smartling-placeholder">
      </ph>
    • Définissez le code d'erreur PlaybackState de manière appropriée. Par exemple, utilisez ERROR_CODE_NOT_AVAILABLE_IN_REGION
    • Définissez le message d'erreur PlaybackState.
    • Définissez l'état PlaybackSate sur STATE_ERROR pour interrompre la lecture. sinon conserver le reste de PlaybackState tel quel.
  • L'utilisateur demande un contenu lorsqu'aucune correspondance exacte n'est disponible. Par exemple, un utilisateur de la version sans frais demandant des contenus réservés aux utilisateurs de la version premium
    • Nous vous recommandons de ne pas renvoyer d'erreur, mais plutôt de donner la priorité de trouver quelque chose de similaire à jouer. L'Assistant se chargera de parler le plus souvent une réponse vocale pertinente avant le début de la lecture.

Lecture avec un intent

L'Assistant peut lancer une application audio ou vidéo, et lancer la lecture en envoyant une avec un lien profond.

L'intent et son lien profond peuvent provenir de différentes sources:

  • Lorsque l'Assistant est au démarrage d'une application mobile, il peut utiliser la recherche Google pour récupérer du contenu balisé fournit une action de visionnage avec un lien.
  • Lorsque l'Assistant lance une appli TV, celle-ci doit inclure un Moteur de recherche TV pour exposer les URI du contenu multimédia. L'Assistant envoie une requête à Le fournisseur de contenu qui doit renvoyer un intent contenant un URI pour le lien profond 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 précisé une action, l'Assistant ajoutera ACTION_VIEW à l'intent.

L'Assistant ajoute EXTRA_START_PLAYBACK avec la valeur true à l'intent qu'il envoie à votre application. Votre application doit lancer la lecture lorsqu'elle reçoit un intent avec EXTRA_START_PLAYBACK.

Gérer les intents actifs

Les utilisateurs peuvent demander à l'Assistant de lire un contenu pendant que votre appli est en cours de lecture d'une requête précédente. Cela signifie que votre application peut recevoir de nouveaux intents lancer la lecture alors que l'activité de lecture est déjà lancée et active ;

Les activités compatibles avec les intents comportant des liens profonds doivent remplacer onNewIntent() pour gérer les nouvelles requêtes.

Au démarrage de la lecture, l'Assistant peut ajouter des indicateurs à l'intent qu'il envoie à votre application. En particulier, elle peut ajouter FLAG_ACTIVITY_CLEAR_TOP ou FLAG_ACTIVITY_NEW_TASK ou les deux. Bien que votre code n'a 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 requête de lecture avec un nouvel URI arrive pendant que l'URI précédent est toujours en cours de lecture. Dans ce cas, nous vous recommandons de tester la réponse de votre application. Vous pouvez utiliser la commande adb outil de ligne de commande pour simuler la situation (la constante 0x14000000 est l'opérateur OR booléen bit à bit 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 depuis un service

Si votre application dispose d'un media browser service qui permet d'établir des connexions depuis l'Assistant, l'Assistant peut démarrer l'application en communiquant avec le service media session Le service de navigateur multimédia ne doit jamais lancer d'activité. L'Assistant lancera votre activité en fonction des PendingIntent que vous aurez définies 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 acceptées à tout moment, y compris pendant l'initialisation. L'Assistant attend que votre contenu multimédia l'application pour définir les actions de lecture avant que l'Assistant n'envoie la première lecture .

Pour démarrer à partir d'un service, l'Assistant implémente les API clientes du navigateur multimédia. Il effectue des appels TransportControls qui déclenchent des rappels d'action de LECTURE sur votre la session multimédia de l'application.

Le schéma suivant illustre l'ordre des appels générés par l'Assistant et les 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'effectue pas attendre la réponse de votre application.

Lancer la lecture avec une session multimédia

Lorsqu'un utilisateur énonce une commande vocale pour écouter de la musique, l'Assistant répond par une courte annonce. Dès que l'annonce est terminée, l'Assistant émet une action de LECTURE. Il n'attend pas d'é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.

Connexion à MediaBrowserService

Pour utiliser un service afin de démarrer votre application, l'Assistant doit pouvoir se connecter au MediaBrowserService de l'application et pour récupérer son MediaSession.Token. Les requêtes de connexion sont gérées onGetRoot() . Il existe deux façons de gérer les requêtes:

  • Accepter toutes les demandes de connexion
  • Accepter uniquement les demandes de connexion provenant de 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 service MediaBrowserService. Vous devez renvoyer une valeur BrowserRoot non nulle. Voici le code applicable issu du lecteur de musique Universal:

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 le nom et la signature de son package. 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. La Lecteur de musique universel gère une liste de signatures et de noms de packages connus. Vous trouverez ci-dessous les noms des packages 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>