Mettre en œuvre la radio

Cette page explique comment implémenter la radio aux niveaux matériel et logiciel.

Composants du système

La pile radio de diffusion comprend les composants suivants.

Architecture de diffusion radio
Figure 1. Architecture de diffusion radio

Application de référence radio

Pour plus de détails sur la façon d'implémenter le contrôle radio, voir Implémentation du contrôle radio .

Un exemple d'application radio Java ( packages/apps/Car/Radio ) sert d'implémentation de référence. Lorsque le service d'application démarre, il demande à Radio Manager d'ouvrir un tuner radio. Ensuite, l'application peut envoyer des demandes au tuner radio, telles que la syntonisation d'une station de radio, d'une fréquence spécifique ou la recherche de la prochaine station de radio disponible. L'application reçoit des mises à jour du Radio Manager et du Tuner Radio dans Radio, telles que les informations sur le programme actuel, les listes de programmes radio, les configurations et les paramètres définis par le fournisseur. L'application Radio de référence prend uniquement en charge la radio AM et FM. Les constructeurs OEM peuvent modifier ou remplacer l'application Radio à leur guise.

Responsable radio

Lorsque l'application demande à Radio Manager d'ouvrir un tuner, Radio Manager ( frameworks/base/core/java/android/hardware/radio/RadioManager.java ) demande au service Broadcast Radio d'ouvrir une session Tuner, puis enveloppe la session dans un Radio Tuner ( frameworks/base/core/java/android/hardware/radio/RadioTuner.java ), qui est renvoyé à l'application. Le tuner radio définit des API (telles que le réglage, le pas et l'annulation) qui peuvent être appelées à partir d'applications radio et envoyer des requêtes au service de radio de diffusion. Les méthodes de rappel ( RadioTuner.Callback ) définies dans Radio Tuner envoient des mises à jour sur la radio diffusée HAL, telles que les informations sur le programme actuel, les listes de programmes et les paramètres définis par le fournisseur, du service de radio de diffusion aux applications.

Service de radiodiffusion

Le service Broadcast Radio ( frameworks/base/services/core/java/com/android/server/broadcastradio ) est le service client de Broadcast Radio HAL. Le service de radio de diffusion coordonne plusieurs gestionnaires de radio avec les HAL de radio de diffusion. Le service de diffusion radio prend en charge les HAL de diffusion radio en langage HAL (HIDL) et en langage de définition d'interface Android (AIDL) . Le service de diffusion radio est lié au AIDL HAL lorsqu'un service AIDL HAL existe ; sinon, le service est lié au HIDL HAL. Le service de diffusion radio crée un module radio pour chaque instance HAL disponible (telle que AM, FM et DAB).

Chaque Manager Radio peut demander au Service Broadcast Radio de créer une session tuner sur le Module Radio correspondant, en fonction du type de radio. Chaque session de tuner peut appeler des méthodes, telles que tune, step et Cancel (définies dans les interfaces HAL) pour effectuer des opérations sur l'instance HAL de radio de diffusion correspondante. Lorsqu'une session de tuner reçoit un rappel de l'instance HAL sur une mise à jour HAL, telle que les informations sur le programme actuel, la liste des programmes, les indicateurs de configuration et les paramètres du fournisseur, les rappels concernant la mise à jour sont envoyés à tous les tuners radio liés au même module radio.

Diffusion radio HAL

Pour en savoir plus sur les interfaces HIDL et AIDL de la radio de diffusion et les différences entre les deux, consultez Interface HAL de radio de diffusion .

Couche d'abstraction du matériel radio de diffusion

Les sections suivantes décrivent comment utiliser la couche d'abstraction matérielle (HAL) pour implémenter la diffusion radio.

Interface de diffusion radio HAL

Le Broadcast radio HAL fournit des structures de données et des interfaces au niveau matériel pour mettre en œuvre la radio de diffusion, telle que la radio AM/FM et DAB.

Interfaces HIDL 2.0 et AIDL

La radio de diffusion HAL utilise les interfaces décrites dans les sections suivantes.

Écouteur d'annonce

IAnnouncementListener est l'interface de rappel pour l'auditeur d'annonces, qui peut être enregistrée sur la radio diffusée HAL pour recevoir des annonces. L'interface dispose des méthodes suivantes :

IAnnonceÉcouteur
Description : Appelé chaque fois que la liste des annonces a changé.
HIDL2.0 oneway onListUpdated(vec<Announcement> announcements)
AIDL oneway void onListUpdated(in Announcement[] announcements)
Fermer la poignée

ICloseHandle est le handle de fermeture générique permettant de supprimer un rappel qui n'a pas besoin d'une interface active.

ICloseHandle
Description : Fermez la poignée.
HIDL2.0 close()
AIDL void close()

Interface de rappel

ITunerCallback est l'interface de rappel appelée par la radio de diffusion HAL pour envoyer des mises à jour au service client HAL.

ITunerCallback
Description : appelé par HAL lorsqu'une opération de réglage (réglage, recherche (en AIDL) ou analyse (en HIDL) et étape réussit) échoue de manière asynchrone.
HIDL2.0 oneway onCurrentProgramInfoChanged(ProgramInfo info)
AIDL void onCurrentProgramInfoChanged(in ProgramInfo info)
Description : Appelé lorsque le réglage, la recherche (en AIDL) ou l'analyse (en HIDL) ou l'étape réussissent.
HIDL2.0 oneway onTuneFailed(Result result, ProgramSelector selector)
AIDL void onTuneFailed(in Result result, in ProgramSelector selector)
Description : Appelé lorsque le réglage, la recherche (en AIDL) ou l'analyse (en HIDL) ou l'étape réussissent.
HIDL2.0 oneway onCurrentProgramInfoChanged(ProgramInfo info)
AIDL void onCurrentProgramInfoChanged(in ProgramInfo info)
Description : Appelé lorsque la liste des programmes est mise à jour ; la taille de chaque morceau doit être limitée à 500 Ko.
HIDL2.0 oneway onProgramListUpdated(ProgramListChunk chunk)
AIDL oneway onProgramListUpdated(ProgramListChunk chunk)
Description : Appelé lorsque l'antenne est connectée ou déconnectée.
HIDL2.0 oneway onAntennaStateChange(bool connected)
AIDL void onCurrentProgramInfoChanged(in ProgramInfo info)
Description : appelé lorsque les valeurs des paramètres spécifiques au fournisseur sont mises à jour en interne dans HAL (ne doit pas être invoqué après l'appel de setParameters par le client HAL).
HIDL2.0 oneway onParametersUpdated(vec<VendorKeyValue> parameters)
AIDL void onParametersUpdated(in VendorKeyValue[] parameters)
Description : Nouveau dans AIDL. Appelé lorsque l'indicateur de configuration est mis à jour en interne dans HAL (ne doit pas être invoqué après l'appel setConfigFlag par le client HAL).
HIDL2.0 N'est pas applicable.
AIDL void onConfigFlagUpdated(in ConfigFlag flag, in boolean value)

Interface HAL de radio de diffusion principale

IBroadcastRadio est l'interface principale pour la diffusion radio HAL. Dans le HAL HIDL 2.0, utilisez l'interface ITunerSession avec le tuner pour appeler des opérations. Cependant, au plus un tuner est actif à la fois (à condition que chaque instance HAL de radio diffusée ne dispose que d'une seule puce de tuner). ITunerSession a été supprimé des interfaces AIDL et ses interfaces ont été déplacées vers IBroadcastRadio .

IBroadcastRadio
Description : Obtenez la description d’un module et de ses capacités.
HIDL2.0 getProperties() generates (Properties properties)
AIDL Properties getProperties()
Description : Récupère la configuration actuelle ou possible de la région AM/FM.
HIDL2.0 getAmFmRegionConfig(bool full) generates (Result result, AmFmRegionConfig config)
AIDL AmFmRegionConfig getAmFmRegionConfig(bool full)
Description : récupère la configuration actuelle de la région DAB.
HIDL2.0 getDabRegionConfig() generates (Result result, vec<DabTableEntry> config)
AIDL DabTableEntry[] getDabRegionConfig()
Description : obtient une image du cache du module radio. Dans AIDL, la taille de l'image doit être inférieure à 1 Mo en raison d'une limite stricte sur le tampon de transaction du classeur.
HIDL2.0 getImage(uint32_t id) generates (vec<uint8_t> image)
AIDL byte[] getImage(in int id)
Description : Enregistre l'écouteur d'annonce.
HIDL2.0 registerAnnouncementListener(vec<AnnouncementType> enabled,IAnnouncementListener listener) generates (Result result, ICloseHandle closeHandle)
AIDL ICloseHandle registerAnnouncementListener(in IAnnouncementListener listener, in AnnouncementType[] enabled)
Description:
  • HIDL HAL : Lorsqu'une nouvelle session tuner est ouverte, l'ancienne session doit être terminée.
  • AIDL HAL : aucune session de tuner n'étant disponible, seul le rappel du tuner doit être défini. S'il existe, l'ancien rappel doit être supprimé.
HIDL2.0 openSession(ITunerCallback callback) génère (Result result, ITunerSession session)
AIDL void setTunerCallback(in ITunerCallback callback)
Description:
  • HIDL HAL : La fermeture d'une session tuner ne doit pas échouer et ne doit être émise qu'une seule fois.
  • AIDL HAL : Il n'y a pas de tuner et seul le rappel du tuner doit être désactivé.
HIDL2.0 close()
AIDL unsetTunerCallback()
Description : Permet de syntoniser un programme spécifié.
HIDL2.0 tune(ProgramSelector program) generates (Result result)
AIDL void tune(in ProgramSelector program)
Description : Recherche le prochain programme valide à l' antenne . Pour éviter toute confusion dans AIDL, scan est renommé seek .
HIDL2.0 scan(bool directionUp, bool skipSubChannel) generates (Result result)
AIDL void seek(in boolean directionUp, in boolean skipSubChannel)
Description : Étapes vers le canal adjacent, qui ne peut être occupé par aucun programme.
HIDL2.0 step(bool directionUp) generates (Result result)
AIDL void step(in boolean directionUp)
Description : Annule les opérations de réglage, de balayage (en HIDL) ou de recherche (en AIDL) ou de pas à pas en attente.
HIDL2.0 cancel()
AIDL void cancel()
Description : applique un filtre à la liste des programmes et commence à envoyer des mises à jour de la liste des programmes via le rappel onProgramListUpdated .
HIDL2.0 startProgramListUpdates(ProgramFilter filter) generates (Result result)
AIDL void startProgramListUpdates(in ProgramFilter filter)
Description : Arrête d'envoyer les mises à jour de la liste des programmes.
HIDL2.0 stopProgramListUpdates()
AIDL void stopProgramListUpdates()
Description : récupère le paramètre actuel d'un indicateur de configuration donné.
HIDL2.0 isConfigFlagSet(ConfigFlag flag) generates (Result result, bool value)
AIDL boolean isConfigFlagSet(in ConfigFlag flag)
Description : définit l'indicateur de configuration donné.
HIDL2.0 setConfigFlag(ConfigFlag flag, bool value) generates (Result result)
AIDL void setConfigFlag(in ConfigFlag flag, boolean value)
Description : définit les valeurs des paramètres spécifiques au fournisseur.
HIDL2.0 setParameters(vec<VendorKeyValue> parameters)

génère ,

(vec<VendorKeyValue> results)
AIDL VendorKeyValue[] setParameters(in VendorKeyValue[] parameters)
Description : récupère les valeurs de paramètres spécifiques au fournisseur.
HIDL2.0 getParameters(vec<string> keys) generates (vec<VendorKeyValue> parameters)
AIDL VendorKeyValue[] getParameters(in String[] keys)

Clarifications de l'interface

Comportement asynchrone

Étant donné que chaque opération de réglage (par exemple, réglage, analyse (en HIDL) ou recherche (en AIDL) et étape) peut prendre du temps et que le thread ne doit pas être bloqué pendant une longue période, l'opération doit planifier des opérations qui prennent beaucoup de temps. pour se produire plus tard et renvoyer rapidement un statut ou un résultat. Dans le détail, chaque opération doit :

  • Annulez toutes les opérations de réglage en attente.
  • Vérifiez si l'opération peut être traitée en fonction des entrées de la méthode et de l'état du tuner.
  • Planifiez la tâche de réglage, puis renvoyez immédiatement le Result (en HIDL) ou status (en AIDL). Si le Result ou status est OK , le rappel du tuner tuneFailed ou currentProgramInfoChanged doit être appelé lorsque la tâche de réglage a échoué (par exemple, en raison d'un délai d'attente) ou est terminée.

De même, startProgramListUpdates planifie également la tâche fastidieuse de mise à jour de la liste des programmes pour qu'elle ait lieu plus tard et pour renvoyer rapidement un statut ou un résultat. La méthode annule d'abord les demandes de mise à jour en attente, puis planifie la tâche de mise à jour et renvoie rapidement le résultat.

Condition de course

En raison du comportement asynchrone des opérations de réglage (par exemple, réglage, balayage (en HIDL) ou recherche (en AIDL) et étape), il existe une condition de concurrence entre l'annulation de l'opération et les opérations de réglage. Si cancel est appelée après que HAL a terminé une opération de réglage et avant la fin du rappel, l'annulation peut être ignorée et le rappel doit se terminer et être reçu par le client HAL.

De même, si stopProgramListUpdates est appelé après que HAL ait terminé une mise à jour de la liste de programmes et avant la fin du rappel onCurrentProgramInfoChanged , stopProgramListUpdates peut être ignoré et le rappel doit se terminer.

Limite de taille des données

Puisqu'il existe une limite stricte sur le tampon de transaction du classeur, la limite de données pour certaines méthodes d'interface transmettant des données d'une taille potentiellement importante est clarifiée dans le HAL AIDL.

  • getImage nécessite que l'image renvoyée fasse moins de 1 Mo.
  • onProgramListUpdate nécessite que chaque chunk fasse moins de 500 Ko. Les listes de programmes plus grandes doivent être divisées par l'implémentation de HAL en plusieurs morceaux et envoyées via plusieurs rappels.

Modifications des structures de données AIDL HAL

En plus des changements dans les interfaces, ces changements ont été appliqués aux structures de données définies dans la diffusion radio AIDL HAL, qui profite de l'AIDL.

  • L'énumération Constant est supprimée dans AIDL et définie comme const int dans IBroadcastRadio . Pendant ce temps, ANTENNA_DISCONNECTED_TIMEOUT_MS est renommé ANTENNA_STATE_CHANGE_TIMEOUT_MS . Un nouveau const int TUNER_TIMEOUT_MS est ajouté. Toutes les opérations de réglage, de recherche et de pas doivent être terminées dans ce délai.
  • Enum RDS et Deemphasis sont supprimés dans AIDL et définis comme const int dans AmFmRegionConfig . En conséquence, fmDeemphasis et fmRds dans ProgramInfo sont déclarés comme int, un résultat de calcul binaire des indicateurs respectifs. Pendant ce temps, D50 et D75 sont renommés respectivement DEEMPHASIS_D50 et DEEMPHASIS_D75 .
  • Les Enum ProgramInfoFlags sont supprimés dans AIDL et définis comme const int dans ProgramInfo avec un préfixe FLAG_ ajouté. En conséquence, infoFlags dans ProgramInfo est déclaré comme int, un résultat de calcul binaire des indicateurs. TUNED est également renommé FLAG_TUNABLE , pour mieux décrire sa définition sur laquelle la station peut être syntonisée.
  • Dans AmFmBandRange , scanSpacing est renommé seekSpacing , puisque scan est renommé seek dans AIDL.
  • Depuis que le concept d' union est introduit dans AIDL, MetadataKey et Metadata définies dans HIDL HAL ne sont plus utilisées. Une Metadata d'union AIDL est définie dans AIDL HAL. Chaque valeur d'énumération précédemment dans MetadataKey est désormais un champ dans Metadata avec le type de chaîne ou int, selon leurs définitions.

Implémentation de la radiocommande

La mise en œuvre du contrôle radio est basée sur MediaSession et MediaBrowse , qui permettent aux applications multimédias et d'assistant vocal de contrôler la radio. Pour plus d'informations, consultez Créer des applications multimédias pour les voitures sur Developer.android.com.

Une implémentation de l'arborescence de navigation multimédia est fournie dans la bibliothèque car-broadcastradio-support dans packages/apps/Car/libs . Cette bibliothèque contient également des extensions de ProgramSelector pour convertir vers et depuis l'URI. Il est recommandé aux implémentations radio d'utiliser cette bibliothèque pour créer l'arborescence de navigation associée.

Sélecteur de source multimédia

Pour assurer une transition transparente entre la radio et les autres applications affichées dans les médias, la bibliothèque car-media-common contient des classes qui doivent être intégrées dans l'application radio. MediaAppSelectorWidget peut être inclus dans le XML de l'application radio (l'icône et la liste déroulante utilisées dans les applications multimédia et radio de référence) :

<com.android.car.media.common.MediaAppSelectorWidget
     android:id="@+id/app_switch_container"
     android:layout_width="@dimen/app_switch_widget_width"
     android:layout_height="wrap_content"
     android:background="@drawable/app_item_background"
     android:gravity="center" />

Ce widget lance AppSelectionFragment , qui affiche une liste de sources multimédias vers lesquelles il est possible de basculer. Si une interface utilisateur autre que celle fournie est souhaitée, vous pouvez créer un widget personnalisé pour lancer AppSelectionFragment lorsque le sélecteur doit être affiché.

AppSelectionFragment newFragment = AppSelectionFragment.create(widget,
            packageName, fullScreen);
    newFragment.show(mActivity.getSupportFragmentManager(), null);

Un exemple d’implémentation est fourni dans l’implémentation de l’application radio de référence, située dans packages/apps/Car/Radio .

Spécifications de contrôle détaillées

L'interface MediaSession (via MediaSession.Callback ) fournit des mécanismes de contrôle pour le programme radio en cours de lecture :

  • onPlay , onStop . (Dé)couper la lecture de la radio.
  • onPause . Pause décalée dans le temps (si prise en charge).
  • onPlayFromMediaId . Lisez n'importe quel contenu à partir d'un dossier de niveau supérieur. Par exemple, « Play FM » ou « Play Radio ».
  • onPlayFromUri . Jouez une fréquence spécifique. Par exemple, « Jouer sur 88,5 FM ».
  • onSkipToNext , onSkipToPrevious . Syntonisez une station suivante ou précédente.
  • onSetRating . Ajouter ou supprimer des favoris.

Le MediaBrowser expose un MediaItem réglable sur trois types de répertoires de niveau supérieur :

  • ( Facultatif ) Programmes (stations). Ce mode est généralement utilisé par les radios à double tuner pour indiquer toutes les stations de radio réglables disponibles à l'emplacement de l'utilisateur.
  • Favoris. Programmes radio ajoutés à la liste des Favoris, certains peuvent être indisponibles (hors de portée de réception).
  • Canaux de bande. Tous les canaux physiquement possibles dans la région actuelle (87.9, 88.1, 88.3, ​​88.5, 88.7, 88.9, 89.1 et ainsi de suite). Chaque groupe possède un répertoire de niveau supérieur distinct.
Arborescence MediaBrowserService
Figure 2. Structure de l'arborescence MediaBrowserService

Chaque élément de chacun de ces dossiers (AM/FM/Programmes) est un MediaItem avec un URI qui peut être utilisé avec MediaSession pour effectuer le réglage. Chaque dossier de niveau supérieur (AM/FM/Programmes) est un MediaItem avec un mediaId qui peut être utilisé avec MediaSession pour déclencher la lecture et est à la discrétion de l'OEM. Par exemple, « Play FM », « Play AM » et « Play Radio » sont toutes des requêtes radio non spécifiques qui utilisent un mediaId à envoyer à l'application radio OEM. C'est à l'application radio de déterminer ce qu'il faut jouer à partir de la requête générique et du mediaId.

Session Média

Étant donné qu'il n'existe aucun concept de pause d'un flux de diffusion, les actions Lecture, Pause et Arrêt ne s'appliquent pas toujours à la radio. Avec la radio, l'action Stop est associée à la mise en sourdine du flux tandis que Play est associée à la suppression de la sourdine.

Certains tuners radio (ou applications) offrent la possibilité de simuler une pause de diffusion en mettant en cache le contenu, puis en le lisant plus tard. Dans de tels cas, utilisez onPause .

La lecture à partir des actions mediaId et URI est destinée à syntoniser une station récupérée depuis l'interface MediaBrowser. Le mediaId est une chaîne arbitraire fournie par l'application radio pour imposer une valeur unique (donc un identifiant donné pointe vers un seul élément) et stable (donc un élément donné a le même identifiant pendant toute la session) avec laquelle identifier une station donnée. . L'URI sera d'un schéma bien défini. En bref, une forme URI de ProgramSelector. Bien que cela préserve l'attribut d'unicité, il n'est pas nécessaire qu'il soit stable, bien qu'il puisse changer lorsque la station passe à une fréquence différente.

De par sa conception, onPlayFromSearch n’est pas utilisé. Il incombe au client (application compagnon) de sélectionner un résultat de recherche dans l’arborescence MediaBrowser. Transférer cette responsabilité à l'application radio augmenterait la complexité, nécessiterait des contrats formels sur la manière dont les requêtes de chaîne devraient apparaître et entraînerait une expérience utilisateur inégale sur différentes plates-formes matérielles.

Remarque : L'application radio ne contient pas d'informations supplémentaires qui seraient utiles pour rechercher un nom de station non exposé au client via l'interface MediaBrowser.

Le passage à la station suivante ou précédente dépend du contexte actuel :

  • Lorsqu'une application est syntonisée sur une station de la liste des Favoris, l'application peut passer à la station suivante de la liste des Favoris.
  • L'écoute d'une station de la liste des programmes peut entraîner la syntonisation de la prochaine station disponible, triée selon le numéro de chaîne.
  • L'écoute d'une chaîne arbitraire peut entraîner la syntonisation sur la chaîne physique suivante, même en l'absence de signal de diffusion.

L'application radio gère ces actions.

La gestion des erreurs

Les actions TransportControls (Play, Stop et Next) ne fournissent pas d'informations indiquant si l'action réussit ou non. La seule façon d'indiquer une erreur est de définir l'état MediaSession sur STATE_ERROR avec un message d'erreur.

L'application radio doit gérer ces actions et soit les exécuter, soit définir un état d'erreur. Si l'exécution de la commande Play n'est pas immédiate, l'état de lecture doit être modifié en STATE_CONNECTING (en cas de réglage direct) ou STATE_SKIPPING_TO_PREVIOUS ou NEXT pendant l'exécution de la commande.

Le client doit surveiller le PlaybackState et vérifier que la session a modifié le programme actuel par rapport à ce qui a été demandé ou est entré dans l'état d'erreur. STATE_CONNECTING ne doit pas dépasser 30 s. Cependant, une syntonisation directe sur une fréquence AM/FM donnée devrait être beaucoup plus rapide.

Ajouter et supprimer des favoris

MediaSession prend en charge la notation, qui peut être utilisée pour contrôler les favoris. onSetRating appelé avec une note de type RATING_HEART ajoute ou supprime la station actuellement écoutée vers ou de la liste des favoris.

Contrairement aux préréglages existants, ce modèle suppose une liste de favoris non ordonnée et illimitée, lorsque chaque favori enregistré a été attribué à un emplacement numérique (généralement 1 à 6). En conséquence, les systèmes basés sur des préréglages seraient incompatibles avec le fonctionnement onSetRating .

La limitation de l'API MediaSession est que seule la station actuellement écoutée peut être ajoutée ou supprimée. Par exemple, les éléments doivent d'abord être sélectionnés avant de pouvoir être supprimés. Il ne s'agit que d'une limitation du client MediaBrowser, telle qu'une application compagnon. L'application radio n'est pas soumise à des restrictions similaires. Cette partie est facultative lorsqu'une application ne prend pas en charge les favoris.

Navigateur multimédia

Pour exprimer quelles fréquences ou noms de canaux physiques (lorsque le réglage sur un canal arbitraire convient à une technologie radio donnée) sont valides pour une région donnée, tous les canaux valides (fréquences) sont répertoriés pour chaque bande. Aux États-Unis, cela équivaut à 101 canaux FM dans la plage de 87,8 à 108,0 MHz (en utilisant un espacement de 0,2 MHz) et 117 canaux AM dans la plage de 530 à 1 700 kHz (en utilisant un espacement de 10 kHz). La radio HD utilisant le même espace de canaux, elle n’est pas présentée séparément.

La liste des programmes de radio actuellement disponibles est plate dans la mesure où elle ne permet pas de schémas d'affichage tels que le regroupement par ensemble de diffusion audio directe (DAB).

Les entrées de la liste des favoris peuvent ne pas être réglables. Par exemple si un programme donné est hors de portée. L'application radio peut détecter ou non si l'entrée peut être réglée au préalable. Si c'est le cas, il se peut que l'entrée ne soit pas marquée comme jouable.

Pour identifier les dossiers de niveau supérieur, le même mécanisme que celui utilisé par Bluetooth est appliqué. Autrement dit, un bundle Extras de l'objet MediaDescription contient un champ spécifique au tuner, tout comme Bluetooth le fait avec EXTRA_BT_FOLDER_TYPE . Dans le cas de la diffusion radio, cela conduit à définir les nouveaux champs suivants dans l'API publique :

  • EXTRA_BCRADIO_FOLDER_TYPE = "android.media.extra.EXTRA_BCRADIO_FOLDER_TYPE" . Une des valeurs suivantes :
    • BCRADIO_FOLDER_TYPE_PROGRAMS = 1 . Programmes actuellement disponibles.
    • BCRADIO_FOLDER_TYPE_FAVORITES = 2 . Favoris.
    • BCRADIO_FOLDER_TYPE_BAND = 3 . Tous les canaux physiques pour une bande donnée.

    Il n'est pas nécessaire de définir des champs de métadonnées personnalisés spécifiques à la radio, car toutes les données pertinentes s'intègrent dans le schéma MediaBrowser.MediaItem existant :

    • Nom du programme (RDS PS, nom du service DAB). MediaDescription.getTitle .
    • Fréquence FM. URI (voir ProgramSelector ) ou MediaDescription.getTitle (si une entrée se trouve dans le dossier BROADCASTRADIO_FOLDER_TYPE_BAND ).
    • Identifiants spécifiques à la radio (RDS PI, DAB SId). MediaDescription.getMediaUri analysé dans ProgramSelector.

    En règle générale, il n'est pas nécessaire de récupérer la fréquence FM pour une entrée du programme en cours ou de la liste des favoris (car le client doit opérer sur les identifiants de média). Cependant, si un tel besoin devait se présenter (par exemple, à des fins d'affichage), il est présent dans l'URI et peut être analysé dans ProgramSelector . Cela dit, il n'est pas recommandé d'utiliser l'URI pour sélectionner des éléments dans la session en cours. Pour plus de détails, consultez ProgramSelector .

    Pour éviter les problèmes de performances ou liés au classeur, le service MediaBrowser doit prendre en charge la pagination :

    Remarque : Par défaut, la pagination est implémentée par défaut dans la variante onLoadChildren() sans gestion des options.

    Les entrées associées de tous les types de listes (chaînes brutes, programmes trouvés et favoris) peuvent avoir des identifiants de média différents (cela dépend de l'application radio ; la bibliothèque de support les aura différents). Les URI (sous forme ProgramSelector) diffèrent entre les chaînes brutes et les programmes trouvés dans la plupart des cas (sauf pour la FM sans RDS), mais sont pour la plupart les mêmes entre les programmes trouvés et les favoris (sauf, par exemple, lorsque AF a été mis à jour).

    Avoir différents mediaIds pour les entrées de différents types de listes permet d'effectuer différentes actions sur celles-ci. Vous pouvez parcourir la liste des Favoris ou la liste Tous les programmes sur onSkipToNext , en fonction du dossier du MediaItem récemment sélectionné (voir MediaSession ).

    Actions de réglage spéciales

    La liste des programmes permet aux utilisateurs de syntoniser une station spécifique, mais ne permet pas aux utilisateurs de faire des demandes générales telles que « Régler sur FM », ce qui pourrait entraîner la syntonisation d'une station récemment écoutée sur la bande FM.

    Pour prendre en charge de telles actions, certains répertoires de niveau supérieur ont l'indicateur FLAG_PLAYABLE (avec FLAG_BROWSABLE pour les dossiers).

    Action S'accorde sur Comment émettre
    Jouer la radio N'importe quelle chaîne radio startService(ACTION_PLAY_BROADCASTRADIO)

    ou

    playFromMediaId(MediaBrowser. getRoot() )
    Jouer sur FM N'importe quelle chaîne FM Lecture à partir du mediaId de la bande FM.

    La détermination du programme à écouter dépend de l'application. Il s'agit généralement de la chaîne la plus récemment écoutée dans la liste donnée. Pour plus de détails sur ACTION_PLAY_BROADCASTRADIO , consultez Intentions de lecture générales .

    Découverte et connexion au service

    PackageManager peut trouver directement l'arborescence radio de diffusion MediaBrowserService. Pour ce faire, appelez resolveService avec l'intention ACTION_PLAY_BROADCASTRADIO (voir Intentions de lecture générales ) et l'indicateur MATCH_SYSTEM_ONLY . Pour rechercher tous les services qui diffusent la radio (il peut y en avoir plusieurs ; par exemple, AM/FM et satellite séparés), utilisez queryIntentServices .

    Le service résolu gère également l'intention de liaison android.media.browse.MediaBrowserService . Ceci est vérifié avec GTS.

    Pour vous connecter au MediaBrowserService sélectionné, créez une instance MediaBrowser pour un composant de service donné et connect . Après avoir établi la connexion, un handle vers MediaSession peut être obtenu via getSessionToken .

    L'application Radio peut restreindre les packages clients autorisés à se connecter dans une implémentation onGetRoot de leur service. L'application doit permettre aux applications système de se connecter sans liste blanche. Pour plus d’informations sur la liste blanche, consultez Accepter le package et la signature de l’application Assistant .

    Si l'application spécifique à la source (par exemple, une application radio) est installée sur un appareil sans une telle prise en charge de la source, elle se présentera toujours comme gérant l'intention ACTION_PLAY_BROADCASTRADIO , mais son arborescence MediaBrowser ne contiendra pas de balises spécifiques à la radio. Ainsi, un client souhaitant vérifier si une source donnée est disponible sur un appareil doit :

    1. Découvrez le service radio (appelez resolveService pour ACTION_PLAY_BROADCASTRADIO ).
    2. Créez MediaBrowser , puis connectez-vous-y.
    3. Déterminez la présence de MediaItem avec EXTRA_BCRADIO_FOLDER_TYPE supplémentaire.

    Remarque : Dans la plupart des cas, le client doit analyser toutes les arborescences MediaBrowser disponibles pour détecter toutes les sources disponibles pour un périphérique donné.

    Noms des groupes

    La liste de bandes est représentée par un ensemble de répertoires de niveau supérieur avec une balise de type de dossier définie sur BCRADIO_FOLDER_TYPE_BAND . Les titres de leurs MediaItem sont des chaînes localisées représentant les noms des groupes. Dans la plupart des cas, ce sera la même chose qu'une traduction en anglais, mais le client ne peut pas se fier à cette hypothèse.

    Pour fournir un mécanisme stable de recherche de certaines bandes, une balise supplémentaire est ajoutée pour les dossiers de bandes, EXTRA_BCRADIO_BAND_NAME_EN . Il s'agit d'un nom non localisé du groupe et ne peut prendre qu'une de ces valeurs prédéfinies :

    • AM
    • FM
    • DAB

    Si le groupe ne figure pas sur cette liste, l'étiquette du nom du groupe ne doit pas être définie. Cependant, si le groupe figure sur la liste, il doit avoir un jeu de balises. La radio HD n'énumère pas de bandes distinctes car elle utilise le même support sous-jacent que l'AM/FM.

    Intentions générales de jeu

    Chaque application dédiée à la lecture d'une source donnée (comme la radio ou le CD) doit gérer une intention de lecture générale pour commencer à lire certains contenus éventuellement à partir d'un état inactif (par exemple, après le démarrage). C'est à l'application de décider comment sélectionner le contenu à lire, mais il s'agit généralement du programme de radio ou de la piste de CD récemment diffusé. Une intention distincte est définie pour chaque source audio :

    • android.car.intent.action.PLAY_BROADCASTRADIO
    • android.car.intent.action.PLAY_AUDIOCD : CD-DA ou CD-Texte
    • android.car.intent.action.PLAY_DATADISC : disque de données optique comme un CD/DVD, mais pas un CD-DA (peut être un CD en mode mixte)
    • android.car.intent.action.PLAY_AUX : Sans préciser quel port AUX
    • android.car.intent.action.PLAY_BLUETOOTH
    • android.car.intent.action.PLAY_USB : Sans préciser quel périphérique USB
    • android.car.intent.action.PLAY_LOCAL : stockage multimédia local (flash intégré)

    Les intentions ont été choisies pour être utilisées pour la commande de lecture générale, car elles résolvent deux problèmes à la fois : la commande de lecture générale elle-même et la découverte de services. L'avantage supplémentaire d'avoir une telle intention serait la possibilité d'exécuter une action aussi simple sans ouvrir la session MediaBrowser.

    La découverte de services est en fait le problème le plus important résolu avec ces intentions. La procédure de découverte de service est ainsi simple et sans équivoque (voir Découverte et connexion au service ).

    Pour faciliter certaines implémentations client, il existe une autre façon d'émettre une telle commande Play (qui doit également être implémentée par l'application radio) : émettre playFromMediaId avec le rootId du nœud racine (utilisé comme mediaId). Bien que le nœud racine ne soit pas censé être jouable, son rootId est une chaîne arbitraire qui peut être rendue consommable en tant que mediaId. Cependant, les clients ne sont pas tenus de comprendre cette nuance.

    Sélecteur de programme

    Bien que mediaId soit suffisant pour sélectionner un canal dans MediaBrowserService , il devient lié à une session et n'est plus cohérent entre les fournisseurs. Dans certains cas, le client peut avoir besoin d'un pointeur absolu (comme une fréquence absolue) pour la maintenir entre les sessions et les appareils.

    À l’ère des émissions de radio numériques, une simple fréquence ne suffit pas pour syntoniser une station spécifique. Par conséquent, utilisez ProgramSelector pour syntoniser une chaîne analogique ou numérique. ProgramSelector se compose de deux parties :

    • Identifiant principal. Un identifiant unique et stable pour une station de radio donnée qui ne change pas mais peut ne pas suffire pour syntoniser cette station. Par exemple, le code RDS PI, qui peut être traduit en indicatif d'appel aux États-Unis.
    • Identifiants secondaires. Identifiants supplémentaires utiles pour syntoniser cette station (par exemple, fréquence), incluant éventuellement des identifiants provenant d'autres technologies radio. Par exemple, une station DAB peut disposer d’une solution de secours en matière de diffusion analogique.

    Pour permettre ProgramSelector de s'intégrer à la solution basée MediaBrowser ou MediaSession , définissez un schéma URI pour le sérialiser. Le schéma est défini comme suit :

    broadcastradio://program/<primary ID type>/<primary ID>?
    <secondary ID type>=<secondary ID>&<secondary ID type>=<secondary ID>
    

    Dans cet exemple, la partie secondaire Identifiers (après le point d'interrogation ( ? )) est facultative et peut être supprimée pour fournir un identifiant stable à utiliser comme mediaId . Par exemple:

    • broadcastradio://program/RDS_PI/1234?AMFM_FREQUENCY=88500&AMFM_FREQUENCY=103300
    • broadcastradio://program/AMFM_FREQUENCY/102100
    • broadcastradio://program/DAB_SID_EXT/14895264?RDS_PI=1234

    La partie autorité (hôte AKA) du program offre une certaine marge d'extension du programme à l'avenir. Les chaînes de type d'identifiant sont spécifiées précisément comme leurs noms dans la définition HAL 2.x de IdentifierType et le format de la valeur est un nombre décimal ou hexadécimal (avec le préfixe 0x ).

    Tous les identifiants spécifiques au fournisseur sont représentés par le préfixe VENDOR_ . Par exemple, VENDOR_0 pour VENDOR_START et VENDOR_1 pour VENDOR_START plus 1. Ces URI sont spécifiques au matériel radio sur lequel ils ont été générés et ne peuvent pas être transférés entre des appareils fabriqués par différents OEM.

    Ces URI doivent être attribués à chaque MediaItem sous les dossiers radio de niveau supérieur. De plus, MediaSession doit prendre en charge à la fois playFromMediaId et playFromUri . Cependant, l'URI est principalement destiné à l'extraction de métadonnées radio (telles que la fréquence FM) et au stockage persistant. Il n'y a aucune garantie que l'URI sera disponible pour tous les éléments multimédias (par exemple, lorsque le type d'ID principal n'est pas encore pris en charge par le framework). D’un autre côté, Media ID fonctionne toujours. Il n'est pas recommandé aux clients d'utiliser l'URI pour sélectionner des éléments de la session MediaBrowser en cours. Utilisez plutôt playFromMediaId . Cela dit, ce n’est pas facultatif pour l’application de desserte et les URI manquants sont réservés à des cas bien justifiés.

    La conception initiale utilisait un seul deux-points au lieu de la séquence :// après la partie schéma. Cependant, le premier n'est pas pris en charge par android.net.Uri pour les références URI hiérarchiques absolues.

    Autres types de sources

    D'autres sources audio peuvent être gérées de la même manière. Par exemple, l'entrée auxiliaire et le lecteur CD audio.

    Une seule application peut servir plusieurs types de sources. Dans de tels cas, il est recommandé de créer un MediaBrowserService distinct pour chaque type de source. Même dans une configuration avec plusieurs sources/MediaBrowserServices servis, il est fortement recommandé d’avoir une seule MediaSession au sein d’une seule application.

    CD audio

    Semblable au CD audio dans la mesure où l'application qui sert de tels disques exposerait MediaBrowser avec une seule entrée consultable (ou plus, si le système dispose d'un changeur de CD), qui à son tour contiendrait toutes les pistes d'un CD donné. Si le système ne connaît pas les pistes de chaque CD (par exemple, lorsque tous les disques sont insérés dans une cartouche en même temps et qu'il ne les lit pas tous), alors MediaItem pour l'ensemble du disque serait simplement PLAYABLE , et non BROWSABLE et PLAYABLE . S'il n'y a pas de disque dans un emplacement donné, l'élément ne sera ni PLAYABLE ni BROWSABLE (mais chaque emplacement doit toujours être présent dans l'arborescence).

    Arborescence des CD audio
    Figure 3. Arborescence des CD audio

    Ces entrées seraient marquées de la même manière que les dossiers de diffusion radio ; ils contiendraient des champs supplémentaires supplémentaires définis dans l'API MediaDescription :

    • EXTRA_CD_TRACK : pour chaque MediaItem sur CD audio, numéro de piste basé sur 1.
    • EXTRA_CD_DISK : numéro de disque basé sur 1.

    Pour les systèmes compatibles CD-Text et les disques compatibles, le MediaItem de niveau supérieur aurait le titre du disque. De même, les MediaItems pour les pistes auraient un titre de piste.

    Entrée auxiliaire

    L'application qui sert d'entrée auxiliaire expose une arborescence MediaBrowser avec une seule entrée (ou plus, lorsque plusieurs ports existent) représentant le port d'entrée AUX. La MediaSession respective prend son mediaId et passe à cette source après avoir reçu la requête playFromMediaId .

    Arborescence AUX
    Figure 4. Structure arborescente AUX

    Chaque entrée AUX MediaItem aurait un champ supplémentaire EXTRA_AUX_PORT_NAME défini sur le nom non localisé du port sans la phrase « AUX ». Par exemple, "AUX 1" aurait été défini sur "1", "AUX front" sur "front" et "AUX" sur une chaîne vide. Dans les langues autres que l'anglais, la balise de nom restera la même chaîne anglaise. Peu probable, comme pour EXTRA_BCRADIO_BAND_NAME_EN , les valeurs sont définies par l'OEM et ne sont pas contraintes à une liste prédéfinie.

    Si le matériel peut détecter les périphériques connectés au port AUX, le matériel doit marquer le Mediatem comme PLAYABLE , uniquement si l'entrée est connectée. Le matériel doit toujours être énuméré (mais pas PLAYABLE ) si rien n'était connecté à ce port. Si le matériel n'a pas une telle capacité, le Mediitem doit toujours être défini sur PLAYABLE .

    Champs supplémentaires

    Définissez les champs suivants:

    • EXTRA_CD_TRACK = "android.media.extra.CD_TRACK"
    • EXTRA_CD_DISK = "android.media.extra.CD_DISK"
    • EXTRA_AUX_PORT_NAME = "android.media.extra.AUX_PORT_NAME"

    Le client doit examiner les Mediitems de niveau supérieur pour les éléments ayant le jeu de champ EXTRA_CD_DISK ou EXTRA_AUX_PORT_NAME .

    Exemples détaillés

    Les exemples suivants abordent la structure de l'arborescence MediaBrowser pour les types de source qui font partie de cette conception.

    Diffusé radio mediaBrowsService (gère ACTION_PLAY_BROADCASTRADIO ):

    • Stations (navigateur) EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_PROGRAMS
      • BBC One (jouable) URI: broadcastradio://program/RDS_PI/1234?AMFM_FREQUENCY=90500
      • ABC 88.1 (Playable) URI: broadcastradio://program/RDS_PI/5678?AMFM_FREQUENCY=88100
      • ABC 88.1 HD1 (Playable) URI: broadcastradio://program/HD_STATION_ID_EXT/158241DEADBEEF?AMFM_FREQUENCY=88100&RDS_PI=5678
      • ABC 88.1 HD2 (Playable) Uri: broadcastradio://program/HD_STATION_ID_EXT/158242DEADBEFE
      • 90.5 FM (jouable) - FM sans Rdsuri: broadcastradio://program/AMFM_FREQUENCY/90500
      • 620 AM (jouable) URI: broadcastradio://program/AMFM_FREQUENCY/620
      • BBC ONE (jouable) URI: broadcastradio://program/DAB_SID_EXT/1E24102?RDS_PI=1234
    • Favoris (navigateur, jouable) EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_FAVORITES
      • BBC One (jouable) URI: broadcastradio://program/RDS_PI/1234?AMFM_FREQUENCY=101300
      • BBC Two (Not Playable) URI: broadcastradio://program/RDS_PI/1300?AMFM_FREQUENCY=102100
    • Am (Browsable, jouable): EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BANDEXTRA_BCRADIO_BAND_NAME_EN="AM"
      • 530 AM (jouable) URI: broadcastradio://program/AMFM_FREQUENCY/530
      • 540 AM (Playable) URI: broadcastradio://program/AMFM_FREQUENCY/540
      • 550 AM (Playable) URI: broadcastradio://program/AMFM_FREQUENCY/550
    • FM (Browsable, Playable): EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BANDEXTRA_BCRADIO_BAND_NAME_EN="FM"
      • 87.7 FM (Playable) URI: broadcastradio://program/AMFM_FREQUENCY/87700
      • 87.9 FM (Playable) URI: broadcastradio://program/AMFM_FREQUENCY/87900
      • 88.1 FM (Playable) URI: broadcastradio://program/AMFM_FREQUENCY/88100
    • Dab (playable): EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BANDEXTRA_BCRADIO_BAND_NAME_EN="DAB"

    Audio CD MediaBrowsserService (gère ACTION_PLAY_AUDIOCD ):

    • Disque 1 (playable) EXTRA_CD_DISK=1
    • Disque 2 (navigateur, jouable) EXTRA_CD_DISK=2
      • Piste 1 (jouable) EXTRA_CD_TRACK=1
      • Piste 2 (jouable) EXTRA_CD_TRACK=2
    • Mon CD de musique (navigable, jouable) EXTRA_CD_DISK=3
      • Tout par moi-même (jouable) EXTRA_CD_TRACK=1
      • Reise, reise (playable) EXTRA_CD_TRACK=2
    • Emplacement vide 4 (non jouable) EXTRA_CD_DISK=4

    AUX MediaBrowSerService (gère ACTION_PLAY_AUX ):

    • AUX Front (playable) EXTRA_AUX_PORT_NAME="front"
    • Aux arrière (jouable) EXTRA_AUX_PORT_NAME="rear"