Questa pagina spiega come implementare la radio a livello hardware e software.
- I componenti del sistema illustrano e descrivono lo stack della tecnologia radio.
- Il livello di astrazione hardware (HAL) della radiodiffusione fornisce strutture dati e interfacce per gli OEM per implementare la radiodiffusione come la radio AM/FM e la radiodiffusione audio digitale (DAB) a livello hardware.
- L'implementazione del controllo radio si basa su
MediaSession
eMediaBrowse
, che consentono alle app multimediali e di assistente vocale di controllare la radio. Oltre al contenuto fornito di seguito, consulta Creare app multimediali per le automobili .
Componenti del sistema
Lo stack radiodiffusione include i seguenti componenti.
App di riferimento radiofonico
Per dettagli su come implementare il controllo radio, vedere Implementazione del controllo radio .
Un'app radio Java di esempio ( packages/apps/Car/Radio
) funge da implementazione di riferimento. All'avvio del servizio app, richiede a Radio Manager di aprire un sintonizzatore radio. Quindi, l'app può inviare richieste al sintonizzatore radio, ad esempio sintonizzarsi su una stazione radio o frequenza specifica o cercare la successiva stazione radio disponibile. L'app riceve aggiornamenti da Radio Manager e Radio Tuner in Radio, come informazioni sul programma corrente, elenchi di programmi radio, configurazioni e parametri definiti dal fornitore. L'app Radio di riferimento supporta solo la radio AM e FM. Gli OEM possono modificare o sostituire l'app Radio come desiderato.
Direttore radiofonico
Quando l'app richiede a Radio Manager di aprire un sintonizzatore, Radio Manager ( frameworks/base/core/java/android/hardware/radio/RadioManager.java
) richiede al servizio Broadcast Radio di aprire una sessione del sintonizzatore e quindi avvolge la sessione in un Radio Tuner ( frameworks/base/core/java/android/hardware/radio/RadioTuner.java
), che viene restituito all'app. Il sintonizzatore radio definisce le API (come tune, step e cancel) che possono essere chiamate dalle app radio e inviare richieste al servizio radiodiffusione. I metodi di richiamata ( RadioTuner.Callback
) definiti in Radio Tuner inviano aggiornamenti sull'HAL della radiodiffusione, ad esempio informazioni sul programma corrente, elenchi di programmi e parametri definiti dal fornitore, dal servizio radiodiffusione alle app.
Servizio radiodiffusione
Il servizio Broadcast Radio ( frameworks/base/services/core/java/com/android/server/broadcastradio
) è il servizio client per Broadcast Radio HAL. Il servizio Broadcast Radio coordina più gestori radio con HAL Broadcast Radio. Il servizio Broadcast Radio supporta gli HAL radiodiffusione HAL Interface Definition Language (HIDL) e Android Interface Definition Language (AIDL) . Il servizio Broadcast Radio si collega all'AIDL HAL quando esiste un servizio AIDL HAL; in caso contrario, il servizio si collega all'HIDL HAL. Il servizio radiodiffusione crea un modulo radio per ogni istanza HAL disponibile (ad esempio AM, FM e DAB).
Ogni Gestore Radio può richiedere al Servizio Radiodiffusione di creare una sessione sintonizzatore sul Modulo Radio corrispondente, in base alla tipologia di radio. Ciascuna sessione del sintonizzatore può richiamare metodi quali tune, step e cancel (definiti nelle interfacce HAL) per eseguire operazioni sull'istanza HAL della radiodiffusione corrispondente. Quando una sessione del sintonizzatore riceve una richiamata dall'istanza HAL su un aggiornamento dell'HAL, come informazioni sul programma corrente, elenco programmi, flag di configurazione e parametri del fornitore, le richiamate sull'aggiornamento vengono inviate a tutti i sintonizzatori radio collegati allo stesso modulo radio.
Trasmissione radiofonica HAL
Per ulteriori informazioni sulle interfacce HIDL e AIDL delle trasmissioni radiofoniche e sulle differenze tra le due, vedere Interfaccia HAL delle trasmissioni radiofoniche .
Livello di astrazione hardware radiodiffusione
Le sezioni seguenti descrivono come utilizzare il livello di astrazione hardware (HAL) per implementare la trasmissione radio.
Interfaccia HAL radiodiffusione
L'HAL Broadcast radio fornisce strutture dati e interfacce a livello hardware per implementare la radio broadcast, come la radio AM/FM e DAB.
Interfacce HIDL 2.0 e AIDL
L'HAL radiodiffusione utilizza le interfacce descritte nelle sezioni seguenti.
- Ascoltatore di annunci
- Chiudere la maniglia
- Interfaccia di richiamata
- Interfaccia HAL radiodiffusione primaria
Ascoltatore di annunci
IAnnouncementListener
è l'interfaccia di richiamata per l'ascoltatore di annunci, che può essere registrato sulla radio HAL per ricevere annunci. L'interfaccia dispone dei seguenti metodi:
IAnnuncioListener | ||
---|---|---|
Descrizione: Chiamato ogni volta che l'elenco degli annunci cambia. | ||
HIDL 2.0 | oneway onListUpdated(vec<Announcement> announcements) | |
AIDL | oneway void onListUpdated(in Announcement[] announcements) |
Chiudere la maniglia
ICloseHandle
è l'handle di chiusura generico per rimuovere un callback che non necessita di un'interfaccia attiva.
IChiloseHandle | ||
---|---|---|
Descrizione: Chiudere la maniglia. | ||
HIDL 2.0 | close() | |
AIDL | void close() |
Interfaccia di richiamata
ITunerCallback
è l'interfaccia di richiamata chiamata dall'HAL della radiodiffusione per inviare aggiornamenti al servizio client HAL.
ITunerCallback | ||
---|---|---|
Descrizione: chiamato dall'HAL quando un'operazione di ottimizzazione (ottimizzazione, ricerca (in AIDL) o scansione (in HIDL) e passaggio ha esito positivo) non riesce in modo asincrono. | ||
HIDL 2.0 | oneway onCurrentProgramInfoChanged(ProgramInfo info) | |
AIDL | void onCurrentProgramInfoChanged(in ProgramInfo info) | |
Descrizione: chiamato quando la sintonizzazione, la ricerca (in AIDL) o la scansione (in HIDL) o il passaggio hanno esito positivo. | ||
HIDL 2.0 | oneway onTuneFailed(Result result, ProgramSelector selector) | |
AIDL | void onTuneFailed(in Result result, in ProgramSelector selector) | |
Descrizione: chiamato quando la sintonizzazione, la ricerca (in AIDL) o la scansione (in HIDL) o il passaggio hanno esito positivo. | ||
HIDL 2.0 | oneway onCurrentProgramInfoChanged(ProgramInfo info) | |
AIDL | void onCurrentProgramInfoChanged(in ProgramInfo info) | |
Descrizione: Chiamato quando viene aggiornata la lista dei programmi; la dimensione di ciascun blocco dovrebbe essere limitata a 500 kiB. | ||
HIDL 2.0 | oneway onProgramListUpdated(ProgramListChunk chunk) | |
AIDL | oneway onProgramListUpdated(ProgramListChunk chunk) | |
Descrizione: Chiamato quando l'antenna è collegata o disconnessa. | ||
HIDL 2.0 | oneway onAntennaStateChange(bool connected) | |
AIDL | void onCurrentProgramInfoChanged(in ProgramInfo info) | |
Descrizione: chiamato quando i valori dei parametri specifici del fornitore vengono aggiornati internamente nell'HAL (non deve essere richiamato dopo aver chiamato setParameters dal client HAL). | ||
HIDL 2.0 | oneway onParametersUpdated(vec<VendorKeyValue> parameters) | |
AIDL | void onParametersUpdated(in VendorKeyValue[] parameters) | |
Descrizione: Novità in AIDL. Chiamato quando il flag di configurazione viene aggiornato internamente nell'HAL (non deve essere richiamato dopo aver chiamato setConfigFlag dal client HAL). | ||
HIDL 2.0 | Non applicabile. | |
AIDL | void onConfigFlagUpdated(in ConfigFlag flag, in boolean value) |
Interfaccia HAL radiodiffusione primaria
IBroadcastRadio
è l'interfaccia principale per la trasmissione radiofonica HAL. Nell'HAL HIDL 2.0, utilizzare l'interfaccia ITunerSession
del sintonizzatore per chiamare le operazioni. Tuttavia, è attivo al massimo un sintonizzatore alla volta (a condizione che ciascuna istanza HAL di trasmissione radio abbia solo un chip di sintonizzazione). ITunerSession
è stato rimosso dalle interfacce AIDL e le sue interfacce sono state spostate su IBroadcastRadio
.
IBroadcastRadio | ||
---|---|---|
Descrizione: ottieni la descrizione di un modulo e delle sue funzionalità. | ||
HIDL 2.0 | getProperties() generates (Properties properties) | |
AIDL | Properties getProperties() | |
Descrizione: recupera la configurazione attuale o possibile della regione AM/FM. | ||
HIDL 2.0 | getAmFmRegionConfig(bool full) generates (Result result, AmFmRegionConfig config) | |
AIDL | AmFmRegionConfig getAmFmRegionConfig(bool full) | |
Descrizione: recupera la configurazione corrente della regione DAB. | ||
HIDL 2.0 | getDabRegionConfig() generates (Result result, vec<DabTableEntry> config) | |
AIDL | DabTableEntry[] getDabRegionConfig() | |
Descrizione: Ottiene un'immagine dalla cache del modulo radio. In AIDL, la dimensione dell'immagine deve essere inferiore a 1 MB a causa di un limite rigido sul buffer delle transazioni del raccoglitore. | ||
HIDL 2.0 | getImage(uint32_t id) generates (vec<uint8_t> image) | |
AIDL | byte[] getImage(in int id) | |
Descrizione: Registra l'ascoltatore dell'annuncio. | ||
HIDL 2.0 | registerAnnouncementListener(vec<AnnouncementType> enabled,IAnnouncementListener listener) generates (Result result, ICloseHandle closeHandle) | |
AIDL | ICloseHandle registerAnnouncementListener(in IAnnouncementListener listener, in AnnouncementType[] enabled) | |
Descrizione:
| ||
HIDL 2.0 | openSession(ITunerCallback callback) genera (Result result, ITunerSession session) | |
AIDL | void setTunerCallback(in ITunerCallback callback) | |
Descrizione:
| ||
HIDL 2.0 | close() | |
AIDL | unsetTunerCallback() | |
Descrizione: Si sintonizza su un programma specifico. | ||
HIDL 2.0 | tune(ProgramSelector program) generates (Result result) | |
AIDL | void tune(in ProgramSelector program) | |
Descrizione: Cerca il prossimo programma valido in onda . Per evitare confusione in AIDL, scan viene rinominata in seek . | ||
HIDL 2.0 | scan(bool directionUp, bool skipSubChannel) generates (Result result) | |
AIDL | void seek(in boolean directionUp, in boolean skipSubChannel) | |
Descrizione: Passa al canale adiacente, che non può essere occupato da nessun programma. | ||
HIDL 2.0 | step(bool directionUp) generates (Result result) | |
AIDL | void step(in boolean directionUp) | |
Descrizione: annulla le operazioni di sintonizzazione, scansione (in HIDL) o ricerca (in AIDL) o passaggi in sospeso. | ||
HIDL 2.0 | cancel() | |
AIDL | void cancel() | |
Descrizione: applica un filtro all'elenco dei programmi e inizia a inviare gli aggiornamenti dell'elenco dei programmi tramite la richiamata onProgramListUpdated . | ||
HIDL 2.0 | startProgramListUpdates(ProgramFilter filter) generates (Result result) | |
AIDL | void startProgramListUpdates(in ProgramFilter filter) | |
Descrizione: interrompe l'invio degli aggiornamenti dell'elenco dei programmi. | ||
HIDL 2.0 | stopProgramListUpdates() | |
AIDL | void stopProgramListUpdates() | |
Descrizione: recupera l'impostazione corrente di un determinato flag di configurazione. | ||
HIDL 2.0 | isConfigFlagSet(ConfigFlag flag) generates (Result result, bool value) | |
AIDL | boolean isConfigFlagSet(in ConfigFlag flag) | |
Descrizione: imposta il flag di configurazione specificato. | ||
HIDL 2.0 | setConfigFlag(ConfigFlag flag, bool value) generates (Result result) | |
AIDL | void setConfigFlag(in ConfigFlag flag, boolean value) | |
Descrizione: imposta i valori dei parametri specifici del fornitore. | ||
HIDL 2.0 | setParameters(vec<VendorKeyValue> parameters) genera , (vec<VendorKeyValue> results) | |
AIDL | VendorKeyValue[] setParameters(in VendorKeyValue[] parameters) | |
Descrizione: recupera i valori dei parametri specifici del fornitore. | ||
HIDL 2.0 | getParameters(vec<string> keys) generates (vec<VendorKeyValue> parameters) | |
AIDL | VendorKeyValue[] getParameters(in String[] keys) |
Chiarimenti sull'interfaccia
Comportamento asincrono
Poiché ciascuna operazione di ottimizzazione (ad esempio, ottimizzazione, scansione (in HIDL) o ricerca (in AIDL) e passaggio) potrebbe richiedere molto tempo e il thread non deve essere bloccato per un lungo periodo, l'operazione dovrebbe pianificare operazioni che richiedono molto tempo verificarsi in seguito e restituire rapidamente uno stato o un risultato. Nel dettaglio ogni operazione dovrà:
- Annulla tutte le operazioni di ottimizzazione in sospeso.
- Verificare se l'operazione può essere elaborata in base agli input del metodo e allo stato del sintonizzatore.
- Pianificare l'attività di ottimizzazione e quindi restituire immediatamente il
Result
(in HIDL) ostatus
(in AIDL). Se ilResult
ostatus
èOK
, è necessario richiamare la richiamata del sintonizzatoretuneFailed
ocurrentProgramInfoChanged
quando l'attività di ottimizzazione non è riuscita (ad esempio a causa di un timeout) o è stata completata.
Allo stesso modo, startProgramListUpdates
pianifica anche l'attività dispendiosa in termini di tempo di aggiornamento dell'elenco dei programmi in modo che avvenga in un secondo momento e restituisca rapidamente uno stato o un risultato. Il metodo annulla innanzitutto le richieste di aggiornamento in sospeso, quindi pianifica l'attività di aggiornamento e restituisce rapidamente il risultato.
Condizione di gara
A causa del comportamento asincrono delle operazioni di ottimizzazione (ad esempio, ottimizzazione, scansione (in HIDL) o ricerca (in AIDL) e passaggio), esiste una condizione di competizione tra l'annullamento dell'operazione e le operazioni di ottimizzazione. Se cancel
viene chiamato dopo che l'HAL ha completato un'operazione di ottimizzazione e prima del completamento della richiamata, l'annullamento può essere ignorato e la richiamata dovrebbe essere completata ed essere ricevuta dal client HAL.
Allo stesso modo, se stopProgramListUpdates
viene chiamato dopo che l'HAL ha completato un aggiornamento dell'elenco di programmi e prima del completamento della richiamata onCurrentProgramInfoChanged
, stopProgramListUpdates
può essere ignorato e la richiamata dovrebbe essere completata.
Limite della dimensione dei dati
Poiché esiste un limite rigido sul buffer delle transazioni del raccoglitore, il limite dei dati per alcuni metodi di interfaccia che passano dati di dimensioni potenzialmente grandi viene chiarito nell'AIDL HAL.
-
getImage
richiede che l'immagine restituita sia inferiore a 1 MB. -
onProgramListUpdate
richiede che ognichunk
sia inferiore a 500 kiB. Gli elenchi di programmi più grandi devono essere suddivisi dall'implementazione HAL in più blocchi e inviati tramite più callback.
Modifiche nelle strutture dati dell'HAL AIDL
Oltre ai cambiamenti nelle interfacce, questi cambiamenti sono stati applicati alle strutture dati definite nella trasmissione radiofonica AIDL HAL, che sfrutta AIDL.
- L'enumerazione
Constant
viene rimossa in AIDL e definita come const int inIBroadcastRadio
. Nel frattempo,ANTENNA_DISCONNECTED_TIMEOUT_MS
viene rinominato inANTENNA_STATE_CHANGE_TIMEOUT_MS
. Viene aggiunto un nuovo const intTUNER_TIMEOUT_MS
. Tutte le operazioni di sintonizzazione, ricerca e step devono essere completate entro questo tempo. - Enum
RDS
eDeemphasis
vengono rimossi in AIDL e definiti come const int inAmFmRegionConfig
. Di conseguenza, siafmDeemphasis
chefmRds
inProgramInfo
sono dichiarati come int, un risultato di calcolo in bit dei rispettivi flag. Nel frattempo,D50
eD75
vengono rinominatiDEEMPHASIS_D50
eDEEMPHASIS_D75
, rispettivamente. - Gli Enum
ProgramInfoFlags
vengono rimossi in AIDL e definiti come const int inProgramInfo
con l'aggiunta del prefissoFLAG_
. Di conseguenza,infoFlags
inProgramInfo
è dichiarato come int, un risultato di calcolo dei bit dei flag. AncheTUNED
è stato rinominatoFLAG_TUNABLE
, per descrivere meglio la definizione su cui la stazione può essere sintonizzata. - In
AmFmBandRange
,scanSpacing
viene rinominato inseekSpacing
, poichéscan
viene rinominata inseek
in AIDL. - Da quando il concetto di unione è stato introdotto in AIDL,
MetadataKey
eMetadata
definiti in HIDL HAL non vengono più utilizzati. IMetadata
dell'unione AIDL sono definiti nell'HAL AIDL. Ogni valore enum precedentemente inMetadataKey
è ora un campo inMetadata
con tipo di stringa o int, a seconda delle relative definizioni.
Implementazione del radiocomando
L'implementazione del controllo radio si basa su MediaSession
e MediaBrowse
, che consentono alle app multimediali e di assistente vocale di controllare la radio. Per ulteriori informazioni, consulta Creare app multimediali per auto su Developer.android.com.
Un'implementazione dell'albero di navigazione multimediale è fornita nella libreria car-broadcastradio-support in packages/apps/Car/libs
. Questa libreria contiene anche estensioni di ProgramSelector per la conversione da e verso URI. Si consiglia che le implementazioni radio utilizzino questa libreria per creare l'albero di navigazione associato.
Commutatore di sorgenti multimediali
Per garantire una transizione fluida tra la radio e le altre app visualizzate nei media, la libreria car-media-common contiene classi che dovrebbero essere integrate nell'app radio. MediaAppSelectorWidget
può essere incluso nell'XML per l'app radio (l'icona e il menu a discesa utilizzati nelle app multimediali e radio di riferimento):
<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" />
Questo widget avvia AppSelectionFragment
, che visualizza un elenco di fonti multimediali a cui è possibile passare. Se si desidera un'interfaccia utente diversa da quella fornita, è possibile creare un widget personalizzato per avviare AppSelectionFragment
quando deve essere visualizzato lo switcher.
AppSelectionFragment newFragment = AppSelectionFragment.create(widget, packageName, fullScreen); newFragment.show(mActivity.getSupportFragmentManager(), null);
Un'implementazione di esempio viene fornita nell'implementazione dell'app radio di riferimento, disponibile in packages/apps/Car/Radio
.
Specifiche di controllo dettagliate
L'interfaccia MediaSession
(tramite MediaSession.Callback
) fornisce meccanismi di controllo per il programma radiofonico attualmente in riproduzione:
-
onPlay
,onStop
. (Dis)disattiva la riproduzione della radio. -
onPause
. Pausa spostata nel tempo (se supportata). -
onPlayFromMediaId
. Riproduci qualsiasi contenuto da una cartella di livello superiore. Ad esempio, "Riproduci FM" o "Riproduci radio". -
onPlayFromUri
. Riproduci una frequenza specifica. Ad esempio, "Riproduci 88.5 FM". -
onSkipToNext
,onSkipToPrevious
. Sintonizzarsi su una stazione successiva o precedente. -
onSetRating
. Aggiungi o rimuovi ai o dai Preferiti.
MediaBrowser espone un MediaItem sintonizzabile su tre tipi di directory di primo livello:
- ( Opzionale ) Programmi (stazioni). Questa modalità viene generalmente utilizzata dalle radio con doppio sintonizzatore per indicare tutte le stazioni radio sintonizzabili disponibili nella posizione dell'utente.
- Preferiti. Programmi radiofonici aggiunti all'elenco dei preferiti, alcuni potrebbero non essere disponibili (fuori portata di ricezione).
- Canali della banda. Tutti i canali fisicamente possibili nella regione corrente (87.9, 88.1, 88.3, 88.5, 88.7, 88.9, 89.1 e così via). Ogni banda ha una directory di primo livello separata.
Ogni elemento in ciascuna di queste cartelle (AM/FM/Programmi) è un MediaItem con un URI che può essere utilizzato con MediaSession per ottimizzare. Ogni cartella di primo livello (AM/FM/Programmi) è un MediaItem con un mediaId che può essere utilizzato con MediaSession per attivare la riproduzione e dipende dalla discrezione dell'OEM. Ad esempio, "Riproduci FM", "Riproduci AM" e "Riproduci radio" sono tutte query radio non specifiche che utilizzano un mediaId per l'invio all'app radio OEM. Spetta all'app radio determinare cosa riprodurre dalla richiesta generica e dal mediaId.
MediaSession
Dato che non esiste il concetto di mettere in pausa un flusso di trasmissione, le azioni Riproduci, Pausa e Interrompi non si applicano sempre alla radio. Con la radio, l'azione Interrompi è associata alla disattivazione dell'audio dello streaming, mentre la Riproduzione è associata alla rimozione della disattivazione.
Alcuni sintonizzatori radio (o app) offrono la possibilità di simulare una pausa nel flusso di trasmissione memorizzando nella cache il contenuto e quindi riproducendolo in un secondo momento. In questi casi, utilizzare onPause
.
La riproduzione dalle azioni mediaId e URI ha lo scopo di sintonizzarsi su una stazione recuperata dall'interfaccia MediaBrowser. Il mediaId è una stringa arbitraria fornita dall'app radio per imporre un valore univoco (quindi un dato ID punta a un solo elemento) e stabile (quindi un dato elemento ha lo stesso ID per tutta la sessione) con cui identificare una determinata stazione . L'URI avrà uno schema ben definito. In breve, una forma URI di ProgramSelector. Sebbene ciò preservi l'attributo di unicità, non è necessario che sia stabile, sebbene possa cambiare quando la stazione si sposta su una frequenza diversa.
In base alla progettazione, onPlayFromSearch
non viene utilizzato. È responsabilità del client (app complementare) selezionare un risultato di ricerca dall'albero MediaBrowser. Trasferire tale responsabilità all'app radio aumenterebbe la complessità, richiederebbe contratti formali su come dovrebbero apparire le query sulle stringhe e comporterebbe un'esperienza utente non uniforme su diverse piattaforme hardware.
Nota: l'app radio non contiene informazioni aggiuntive utili per cercare il nome di una stazione non esposta al client tramite l'interfaccia MediaBrowser.
Il passaggio alla stazione successiva o precedente dipende dal contesto attuale:
- Quando un'app è sintonizzata su una stazione dall'elenco dei Preferiti, l'app può passare alla stazione successiva dall'elenco dei Preferiti.
- L'ascolto di una stazione dall'elenco dei programmi può comportare la sintonizzazione sulla successiva stazione disponibile, ordinata in base al numero del canale.
- L'ascolto di un canale arbitrario potrebbe comportare la sintonizzazione sul canale fisico successivo, anche in assenza di segnale di trasmissione.
L'app radio gestisce queste azioni.
Gestione degli errori
Le azioni TransportControls
(Riproduci, Interrompi e Successivo) non forniscono feedback sulla riuscita o meno dell'azione. L'unico modo per indicare un errore è impostare lo stato MediaSession su STATE_ERROR
con un messaggio di errore.
L'app radio deve gestire tali azioni ed eseguirle o impostare uno stato di errore. Se l'esecuzione del comando Play non è immediata, lo stato di riproduzione deve essere modificato in STATE_CONNECTING
(in caso di sintonizzazione diretta) o STATE_SKIPPING_TO_PREVIOUS
o NEXT
mentre il comando viene eseguito.
Il client deve osservare PlaybackState
e verificare che la sessione abbia modificato il programma corrente in quanto richiesto o inserito nello stato di errore. STATE_CONNECTING
non deve superare i 30 s. Tuttavia, una sintonizzazione diretta su una determinata frequenza AM/FM dovrebbe funzionare molto più velocemente.
Aggiungi e rimuovi i preferiti
MediaSession dispone del supporto per la classificazione, che può essere utilizzato per controllare i Preferiti. onSetRating
chiamato con una valutazione di tipo RATING_HEART
aggiunge o rimuove la stazione attualmente sintonizzata da o verso l'elenco dei preferiti.
Contrariamente alle preimpostazioni legacy, questo modello presuppone un elenco di Preferiti non ordinato e illimitato, in cui ciascun preferito salvato è stato assegnato a uno slot numerico (tipicamente da 1 a 6). Di conseguenza, i sistemi basati su preimpostazioni sarebbero incompatibili con il funzionamento onSetRating
.
La limitazione dell'API MediaSession è che è possibile aggiungere o rimuovere solo la stazione attualmente sintonizzata. Ad esempio, gli elementi devono essere selezionati prima di poter essere rimossi. Questa è solo una limitazione del client MediaBrowser, come un'app complementare. L'app radio non ha le stesse limitazioni. Questa parte è facoltativa quando un'app non supporta i Preferiti.
MediaBrowser
Per esprimere quali frequenze o nomi di canali fisici (quando la sintonizzazione su un canale arbitrario è adatto per una determinata tecnologia radio) sono validi per una determinata regione, tutti i canali validi (frequenze) sono elencati per ciascuna banda. Nella regione degli Stati Uniti, ciò equivale a 101 canali FM nell'intervallo da 87,8 a 108,0 MHz (utilizzando una spaziatura di 0,2 MHz) e 117 canali AM nell'intervallo da 530 a 1700 kHz (utilizzando una spaziatura di 10 kHz). Poiché la radio HD utilizza lo stesso spazio di canali, non viene presentata separatamente.
L'elenco dei programmi radiofonici attualmente disponibili è piatto in quanto non consente schemi di visualizzazione come il raggruppamento per ensemble di trasmissione audio diretta (DAB).
Le voci nell'elenco dei preferiti potrebbero non essere sintonizzabili. Ad esempio se un determinato programma è fuori portata. L'app radio potrebbe rilevare o meno se la voce può essere sintonizzata in anticipo. In tal caso, potrebbe non contrassegnare la voce come riproducibile.
Per identificare le cartelle di livello superiore viene applicato lo stesso meccanismo utilizzato da Bluetooth. Cioè, un pacchetto Extra dell'oggetto MediaDescription
contiene un campo specifico del sintonizzatore proprio come fa Bluetooth con EXTRA_BT_FOLDER_TYPE
. Nel caso delle trasmissioni radiofoniche ciò porta a definire nelle API pubbliche i seguenti nuovi campi:
-
EXTRA_BCRADIO_FOLDER_TYPE = "android.media.extra.EXTRA_BCRADIO_FOLDER_TYPE"
. Uno dei seguenti valori:-
BCRADIO_FOLDER_TYPE_PROGRAMS = 1
. Programmi attualmente disponibili. -
BCRADIO_FOLDER_TYPE_FAVORITES = 2
. Preferiti. -
BCRADIO_FOLDER_TYPE_BAND = 3
. Tutti i canali fisici per una determinata banda.
Non è necessario definire campi di metadati personalizzati specifici della radio, poiché tutti i dati rilevanti rientrano nello schema
MediaBrowser.MediaItem
esistente:- Nome del programma (RDS PS, nome del servizio DAB).
MediaDescription.getTitle
. - Frequenza FM. URI (vedi ProgramSelector ) o
MediaDescription.getTitle
(se una voce si trova nella cartellaBROADCASTRADIO_FOLDER_TYPE_BAND
). - Identificatori radio specifici (RDS PI, DAB SId).
MediaDescription.getMediaUri
analizzato in ProgramSelector.
In genere, non è necessario recuperare la frequenza FM per una voce nel programma corrente o nell'elenco dei preferiti (poiché il client dovrebbe operare su ID multimediali). Tuttavia, se tale necessità dovesse verificarsi (ad esempio, per scopi di visualizzazione), è presente nell'URI e può essere analizzata in
ProgramSelector
. Detto questo, non è consigliabile utilizzare l'URI per selezionare elementi all'interno della sessione corrente. Per i dettagli, vedereProgramSelector
.Per evitare problemi di prestazioni o relativi al raccoglitore, il servizio MediaBrowser deve supportare l'impaginazione:
-
EXTRA_PAGE
-
EXTRA_PAGE_SIZE
- Parametri aggiuntivi per
subscribe()
Nota: per impostazione predefinita, l'impaginazione è implementata nella variante
onLoadChildren()
senza gestione delle opzioni.Le voci correlate da tutti i tipi di elenchi (canali grezzi, programmi trovati e preferiti) possono avere mediaId diversi (dipende dall'app radio; la libreria di supporto li avrà diversi). Gli URI (nella forma ProgramSelector) differiscono tra i canali grezzi e i programmi trovati nella maggior parte dei casi (eccetto FM senza RDS), ma sono per lo più gli stessi tra i programmi trovati e i preferiti (tranne, ad esempio, quando AF è stato aggiornato).
Avere mediaId diversi per voci provenienti da diversi tipi di elenchi rende possibile intraprendere azioni diverse su di essi. È possibile scorrere l'elenco dei Preferiti o l'elenco Tutti i programmi su
onSkipToNext
, a seconda della cartella delMediaItem
recentemente selezionato (vedere MediaSession ).Azioni di sintonizzazione speciali
L'elenco dei programmi consente agli utenti di sintonizzarsi su una stazione specifica, ma non consente agli utenti di effettuare richieste generali come "Sintonizzati su FM", che potrebbero comportare la sintonizzazione su una stazione ascoltata di recente sulla banda FM.
Per supportare tali azioni, alcune directory di livello superiore hanno il flag
FLAG_PLAYABLE
impostato (insieme aFLAG_BROWSABLE
per le cartelle).Azione Sintonizzati su Come emettere Ascolta la radio Qualsiasi canale radiofonico startService(ACTION_PLAY_BROADCASTRADIO)
O
playFromMediaId(MediaBrowser. getRoot() )
Ascolta FM Qualsiasi canale FM Riproduci dal mediaId
della banda FM.La decisione su quale programma sintonizzarsi spetta all'app. Solitamente si tratta del canale sintonizzato più recentemente dall'elenco fornito. Per dettagli su
ACTION_PLAY_BROADCASTRADIO
, vedere Intenti di gioco generali .Individuazione e connessione al servizio
PackageManager
può trovare direttamente l'albero delle radiodiffusioni che serve MediaBrowserService. Per fare ciò,resolveService
con l'intentoACTION_PLAY_BROADCASTRADIO
(vedi Intenti di gioco generali ) e il flagMATCH_SYSTEM_ONLY
. Per trovare tutti i servizi che servono la radio (potrebbero essercene più di uno; ad esempio, AM/FM e satellite separati), utilizzarequeryIntentServices
.Il servizio risolto gestisce anche l'intento di associazione
android.media.browse.MediaBrowserService
. Questo viene verificato con GTS.Per connetterti al MediaBrowserService selezionato, crea un'istanza
MediaBrowser
per un determinato componente del servizio econnect
. Dopo aver stabilito la connessione, è possibile ottenere un handle per MediaSession tramitegetSessionToken
.L'app Radio può limitare i pacchetti client autorizzati a connettersi in un'implementazione
onGetRoot
del proprio servizio. L'app dovrebbe consentire alle app di sistema di connettersi senza inserirle nella whitelist. Per maggiori dettagli sull'inserimento nella whitelist, vedi Accettare il pacchetto e la firma dell'app dell'Assistente .Se l'app specifica della sorgente (ad esempio, un'app radio) è installata su un dispositivo senza tale supporto della sorgente, si pubblicizzerebbe comunque come in grado di gestire l'intento
ACTION_PLAY_BROADCASTRADIO
, ma il suo albero MediaBrowser non conterrebbe tag specifici della radio. Pertanto, un cliente che voglia verificare se una determinata fonte è disponibile su un dispositivo, deve:- Scopri il servizio radio (
resolveService
perACTION_PLAY_BROADCASTRADIO
). - Crea
MediaBrowser
e poi connettiti ad esso. - Determina la presenza di
MediaItem
conEXTRA_BCRADIO_FOLDER_TYPE
extra.
Nota: nella maggior parte dei casi, il client deve eseguire la scansione di tutti gli alberi MediaBrowser disponibili per rilevare tutte le origini disponibili per un determinato dispositivo.
Nomi delle bande
L'elenco delle bande è rappresentato da un insieme di directory di livello superiore con un tag del tipo di cartella impostato su
BCRADIO_FOLDER_TYPE_BAND
. I titoli dei loroMediaItem
sono stringhe localizzate che rappresentano i nomi delle band. Nella maggior parte dei casi sarà uguale alla traduzione in inglese, ma il cliente non può dipendere da questo presupposto.Per fornire un meccanismo stabile per la ricerca di determinate band, è stato aggiunto un tag aggiuntivo per le cartelle delle band,
EXTRA_BCRADIO_BAND_NAME_EN
. Questo è un nome non localizzato della band e può assumere solo uno di questi valori predefiniti:-
AM
-
FM
-
DAB
Se la band non è presente in questo elenco, il tag del nome della band non deve essere impostato. Tuttavia, se la band è nell'elenco, deve avere un tag impostato. La radio HD non elenca bande separate poiché utilizza lo stesso mezzo sottostante di AM/FM.
Intenzioni di gioco generali
Ogni app dedicata alla riproduzione di una determinata sorgente (come radio o CD) deve gestire un intento di riproduzione generale per avviare la riproduzione di alcuni contenuti possibilmente dallo stato inattivo (ad esempio dopo l'avvio). Spetta all'app selezionare il contenuto da riprodurre, ma di solito si tratta del programma radiofonico o della traccia del CD riprodotto di recente. Esiste un intento separato definito per ciascuna sorgente audio:
-
android.car.intent.action.PLAY_BROADCASTRADIO
-
android.car.intent.action.PLAY_AUDIOCD
: CD-DA o CD-Text -
android.car.intent.action.PLAY_DATADISC
: disco dati ottico come CD/DVD, ma non CD-DA (potrebbe essere un CD in modalità mista) -
android.car.intent.action.PLAY_AUX
: senza specificare quale porta AUX -
android.car.intent.action.PLAY_BLUETOOTH
-
android.car.intent.action.PLAY_USB
: senza specificare quale dispositivo USB -
android.car.intent.action.PLAY_LOCAL
: archiviazione multimediale locale (flash integrato)
Gli intenti sono stati scelti per essere utilizzati per il comando di gioco generale, perché risolvono due problemi contemporaneamente: il comando di gioco generale stesso e il rilevamento del servizio. Un ulteriore vantaggio di avere tale intento sarebbe la possibilità di eseguire un'azione così semplice senza aprire la sessione di MediaBrowser.
L'individuazione dei servizi è in realtà il problema più importante risolto con questi intenti. La procedura per l'individuazione del servizio è semplice e inequivocabile in questo modo (vedi Individuazione e connessione al servizio ).
Per rendere più semplici alcune implementazioni client, esiste un modo alternativo di emettere tale comando Play (che deve essere implementato anche dall'app radio): emettere
playFromMediaId
con il rootId del nodo root (utilizzato come mediaId). Sebbene il nodo radice non sia concepito per essere riproducibile, il suo rootId è una stringa arbitraria che può essere resa utilizzabile come mediaId. Tuttavia, i clienti non sono tenuti a comprendere questa sfumatura.Selettore di programma
Sebbene
mediaId
sia sufficiente per selezionare un canale daMediaBrowserService
, diventa vincolato a una sessione e non è coerente tra i provider. In alcuni casi il client potrebbe aver bisogno di un puntatore assoluto (come una frequenza assoluta) per mantenerlo tra sessioni e dispositivi.Nell'era delle trasmissioni radiofoniche digitali, una semplice frequenza non è sufficiente per sintonizzarsi su una determinata stazione. Pertanto, utilizzare
ProgramSelector
per sintonizzarsi su un canale analogico o digitale.ProgramSelector
è composto da due parti:- Identificatore primario. Un identificatore univoco e stabile per una determinata stazione radio che non cambia ma potrebbe non essere sufficiente per sintonizzarsi su quella stazione. Ad esempio, il codice RDS PI, che può essere tradotto nell'identificativo di chiamata negli Stati Uniti.
- Identificatori secondari. Identificatori aggiuntivi utili per sintonizzarsi su quella stazione (ad esempio, frequenza), eventualmente includendo identificatori di altre tecnologie radio. Ad esempio, una stazione DAB potrebbe avere un fallback di trasmissione analogica.
Per consentire
ProgramSelector
di adattarsi alla soluzione basata suMediaBrowser
oMediaSession
, definire uno schema URI per serializzarlo. Lo schema è definito come segue:broadcastradio://program/<primary ID type>/<primary ID>? <secondary ID type>=<secondary ID>&<secondary ID type>=<secondary ID>
In questo esempio, la parte secondaria degli identificatori (dopo il punto interrogativo (
?
)) è facoltativa e può essere rimossa per fornire un identificatore stabile da utilizzare comemediaId
. Per esempio:-
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 parte del
program
relativa all'autorità (AKA host) offre spazio per l'estensione del programma in futuro. Le stringhe del tipo di identificatore sono specificate con precisione come i relativi nomi nella definizione HAL 2.x diIdentifierType
e il formato del valore è un numero decimale o esadecimale (con prefisso0x
).Tutti gli identificatori specifici del fornitore sono rappresentati dal prefisso
VENDOR_
. Ad esempio,VENDOR_0
perVENDOR_START
eVENDOR_1
perVENDOR_START
più 1. Tali URI sono specifici dell'hardware radio su cui sono stati generati e non possono essere trasferiti tra dispositivi realizzati da OEM diversi.Questi URI devono essere assegnati a ciascun MediaItem nelle cartelle radio di livello superiore. Inoltre, MediaSession deve supportare sia
playFromMediaId
cheplayFromUri
. Tuttavia, l'URI è destinato principalmente all'estrazione di metadati radio (come la frequenza FM) e all'archiviazione persistente. Non vi è alcuna garanzia che l'URI sarà disponibile per tutti gli elementi multimediali (ad esempio, quando il tipo di ID primario non è ancora supportato dal framework). D'altra parte, Media ID funziona sempre. Non è consigliabile che i client utilizzino l'URI per selezionare elementi dalla sessione MediaBrowser corrente. Utilizzare inveceplayFromMediaId
. Detto questo, non è facoltativo per l'app di servizio e gli URI mancanti sono riservati a casi ben giustificati.Il progetto iniziale utilizzava singoli due punti invece della sequenza
://
dopo la parte dello schema. Tuttavia, il primo non è supportato daandroid.net.Uri
per i riferimenti URI gerarchici assoluti.Altri tipi di fonti
Altre sorgenti audio possono essere gestite in modo simile. Ad esempio, l'ingresso ausiliario e il lettore CD audio.
Una singola app può servire più tipi di fonti. In questi casi, è consigliabile creare un MediaBrowserService separato per ogni tipo di origine. Anche in una configurazione con più origini servite/MediaBrowserServices, è fortemente consigliabile avere una singola MediaSession all'interno di una singola app.
CD audio
Simile al CD audio in quanto l'app che serve tali dischi esporrebbe MediaBrowser con una singola voce esplorabile (o più, se il sistema dispone di un cambia CD), che a sua volta conterrebbe tutte le tracce di un determinato CD. Se il sistema non conosce le tracce su ogni CD (ad esempio, quando tutti i dischi vengono inseriti in una cartuccia contemporaneamente e non li legge tutti), allora MediaItem per l'intero disco sarebbe solo
PLAYABLE
, nonBROWSABLE
piùPLAYABLE
. Se in un determinato slot non fosse presente alcun disco, l'oggetto non sarebbe néPLAYABLE
néBROWSABLE
(ma ogni slot deve essere sempre presente nell'albero).Queste voci verrebbero contrassegnate in modo simile alle cartelle delle trasmissioni radiofoniche; conterrebbero campi extra aggiuntivi definiti nell'API MediaDescription:
-
EXTRA_CD_TRACK
: per ogniMediaItem
su CD audio, numero di traccia in base 1. -
EXTRA_CD_DISK
: numero del disco in base 1.
Per i sistemi abilitati per CD-Text e i dischi compatibili, il MediaItem di livello superiore avrà un titolo del disco. Allo stesso modo, i MediaItem per le tracce avrebbero un titolo della traccia.
Ingresso ausiliario
L'app che fornisce l'input ausiliario espone un albero MediaBrowser con una singola voce (o più, quando esistono più porte) che rappresenta la porta di ingresso AUX. La rispettiva MediaSession prende il suo mediaId e passa a quella fonte dopo aver ricevuto la richiesta
playFromMediaId
.Ogni voce AUX MediaItem avrebbe un campo aggiuntivo
EXTRA_AUX_PORT_NAME
impostato sul nome non localizzato della porta senza la frase "AUX". Ad esempio, "AUX 1" dovrebbe essere impostato su "1", "AUX front" su "front" e "AUX" su una stringa vuota. Nelle versioni locali non inglesi, il tag name rimarrebbe la stessa stringa inglese. È improbabile che perEXTRA_BCRADIO_BAND_NAME_EN
, i valori sono definiti da OEM e non vincolati a un elenco predefinito.Se l'hardware è in grado di rilevare i dispositivi collegati alla porta AUX, l'hardware dovrebbe contrassegnare il MediaItem come
PLAYABLE
, solo se l'input è collegato. L'hardware dovrebbe essere ancora elencato (ma nonPLAYABLE
) se nulla era collegato a questa porta. Se l'hardware non ha tali capacità, il MediaItem deve essere sempre impostato suPLAYABLE
.Campi extra
Definire i seguenti campi:
-
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"
Il client deve rivedere i mediaitem di livello superiore per elementi con il set di campo extra
EXTRA_CD_DISK
oEXTRA_AUX_PORT_NAME
.Esempi dettagliati
I seguenti esempi affrontano la struttura dell'albero di Mediabrowser per i tipi di origine che fanno parte di questo design.
Broadcast Radio MediaBrowsService (gestisce
ACTION_PLAY_BROADCASTRADIO
):- Stazioni (browsable)
EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_PROGRAMS
- BBC One (Playable) 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 (giocabile) - FM senza RDSuri:
broadcastradio://program/AMFM_FREQUENCY/90500
- 620 am (giocabile) URI:
broadcastradio://program/AMFM_FREQUENCY/620
- BBC One (Playable) Uri:
broadcastradio://program/DAB_SID_EXT/1E24102?RDS_PI=1234
- BBC One (Playable) Uri:
- Preferiti (browsable, giocabile)
EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_FAVORITES
- BBC One (Playable) Uri:
broadcastradio://program/RDS_PI/1234?AMFM_FREQUENCY=101300
- BBC Two (non giocabile) URI:
broadcastradio://program/RDS_PI/1300?AMFM_FREQUENCY=102100
- BBC One (Playable) Uri:
- AM (browsable, playable):
EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BANDEXTRA_BCRADIO_BAND_NAME_EN="AM"
- 530 am (giocabile) URI:
broadcastradio://program/AMFM_FREQUENCY/530
- 540 am (giocabile) URI:
broadcastradio://program/AMFM_FREQUENCY/540
- 550 am (giocabile) URI:
broadcastradio://program/AMFM_FREQUENCY/550
- 530 am (giocabile) URI:
- FM (browsable, playable):
EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BANDEXTRA_BCRADIO_BAND_NAME_EN="FM"
- 87.7 FM (giocabile) URI:
broadcastradio://program/AMFM_FREQUENCY/87700
- 87.9 FM (giocabile) URI:
broadcastradio://program/AMFM_FREQUENCY/87900
- 88.1 FM (giocabile) URI:
broadcastradio://program/AMFM_FREQUENCY/88100
- 87.7 FM (giocabile) URI:
- Dab (playable):
EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BANDEXTRA_BCRADIO_BAND_NAME_EN="DAB"
Audio CD MediaBrowsService (gestisce
ACTION_PLAY_AUDIOCD
):- Disco 1 (giocabile)
EXTRA_CD_DISK=1
- Disco 2 (sfollabile, giocabile)
EXTRA_CD_DISK=2
- Traccia 1 (playable)
EXTRA_CD_TRACK=1
- Traccia 2 (playable)
EXTRA_CD_TRACK=2
- Traccia 1 (playable)
- My Music CD (browsable, playable)
EXTRA_CD_DISK=3
- Tutto da me (giocabile)
EXTRA_CD_TRACK=1
- Reise, Reise (Playable)
EXTRA_CD_TRACK=2
- Tutto da me (giocabile)
- Slot vuoto 4 (non giocabile)
EXTRA_CD_DISK=4
Aux MediaBrowsService (gestisce
ACTION_PLAY_AUX
):- Aux Front (Playable)
EXTRA_AUX_PORT_NAME="front"
- Aux posteriore (giocabile)
EXTRA_AUX_PORT_NAME="rear"
-