Radio implementieren

Mit Sammlungen den Überblick behalten Sie können Inhalte basierend auf Ihren Einstellungen speichern und kategorisieren.

Auf dieser Seite wird erläutert, wie Funk auf Hardware- und Softwareebene implementiert wird.

  • Systemkomponenten veranschaulicht und beschreibt den Funktechnologie-Stack.
  • Broadcast Radio Hardware Abstraction Layer stellt Datenstrukturen und Schnittstellen für OEMs bereit, um Rundfunk wie AM/FM und DAB-Radio (Digital Audio Broadcasting) auf Hardwareebene zu implementieren.
  • Die Implementierung der Radiosteuerung basiert auf MediaSession und MediaBrowse , die es Medien- und Sprachassistenten-Apps ermöglichen, das Radio zu steuern. Zusätzlich zu den unten bereitgestellten Inhalten finden Sie weitere Informationen unter Erstellen von Medien-Apps für Autos .

Systemkomponenten

Der Rundfunkstapel umfasst die folgenden Komponenten.

Rundfunkarchitektur
Abbildung 1. Rundfunkarchitektur

Radio-Referenz-App

Einzelheiten zur Implementierung der Funksteuerung finden Sie unter Implementierung der Funksteuerung .

Als Referenzimplementierung dient eine Beispiel-Java-Radio-App ( packages/apps/Car/Radio ). Wenn der App-Dienst gestartet wird, fordert er Radio Manager auf, einen Radio-Tuner zu öffnen. Dann kann die App Anfragen an den Radiotuner senden, z. B. zum Einstellen eines bestimmten Radiosenders, einer bestimmten Frequenz oder zum Suchen des nächsten verfügbaren Radiosenders. Die App erhält Updates vom Radio Manager und Radio Tuner in Radio, wie z. B. aktuelle Programminformationen, Radioprogrammlisten, Konfigurationen und herstellerdefinierte Parameter. Die Referenz-Radio-App unterstützt nur AM- und FM-Radio. OEMs können die Radio-App nach Belieben modifizieren oder ersetzen.

Radiomanager

Wenn die App Radio Manager auffordert, einen Tuner zu öffnen, fordert der Radio Manager ( frameworks/base/core/java/android/hardware/radio/RadioManager.java ) den Broadcast Radio Service auf, eine Tuner-Sitzung zu öffnen, und umschließt die Sitzung dann in einer Radio Tuner ( frameworks/base/core/java/android/hardware/radio/RadioTuner.java ), der an die App zurückgegeben wird. Der Radio-Tuner definiert APIs (wie Tune, Step und Cancel), die von Radio-Apps aufgerufen werden können und Anfragen an den Broadcast Radio Service senden. Rückrufmethoden ( RadioTuner.Callback ), die in Radio Tuner definiert sind, senden Aktualisierungen über die Rundfunk-HAL, wie z. B. aktuelle Programminformationen, Programmlisten und anbieterdefinierte Parameter, vom Rundfunkdienst an Apps.

Rundfunkdienst

Der Broadcast Radio Service ( frameworks/base/services/core/java/com/android/server/broadcastradio ) ist der Client-Service für Broadcast Radio HAL. Der Broadcast Radio Service koordiniert mehrere Radio Manager mit Broadcast Radio HALs. Der Broadcast Radio Service unterstützt Rundfunk-HALs der HAL-Schnittstellendefinitionssprache (HIDL) und der Android-Schnittstellendefinitionssprache (AIDL) . Der Rundfunkdienst verbindet sich mit dem AIDL HAL, wenn ein AIDL HAL-Dienst existiert; andernfalls wird der Dienst mit der HIDL HAL verknüpft. Der Broadcast Radio Service erstellt ein Radiomodul für jede verfügbare HAL-Instanz (z. B. AM, FM und DAB).

Jeder Radio Manager kann den Broadcast Radio Service auffordern, eine Tuner-Session auf dem entsprechenden Radiomodul basierend auf dem Radiotyp zu erstellen. Jede Tuner-Session kann Methoden aufrufen, wie z. B. tune, step und cancel (definiert in HAL-Schnittstellen), um Operationen an der entsprechenden Rundfunk-HAL-Instanz auszuführen. Wenn eine Tuner-Sitzung bei einem HAL-Update einen Rückruf von der HAL-Instanz erhält, wie z. B. aktuelle Programminformationen, Programmliste, Konfigurations-Flags und Herstellerparameter, werden Rückrufe über das Update an alle Radio-Tuner gesendet, die mit demselben Radiomodul verbunden sind.

Radiosender HAL

Um mehr über die HIDL- und AIDL-Schnittstellen des Rundfunks und die Unterschiede zwischen den beiden zu erfahren, siehe HAL-Schnittstelle des Rundfunks .

Rundfunk-Hardware-Abstraktionsschicht

In den folgenden Abschnitten wird beschrieben, wie Sie mit der Hardwareschicht arbeiten, um Rundfunk zu implementieren.

Rundfunk-HAL-Schnittstelle

Die Rundfunk-HAL stellt Datenstrukturen und Schnittstellen auf Hardwareebene bereit, um Rundfunk, wie etwa AM/FM- und DAB-Radio, zu implementieren.

HIDL 2.0- und AIDL-Schnittstellen

Das Rundfunkgerät HAL verwendet die in den folgenden Abschnitten beschriebenen Schnittstellen.

Ansage-Hörer

IAnnouncementListener ist die Callback-Schnittstelle für den Ansage-Listener, der im Rundfunk-HAL registriert werden kann, um Ansagen zu empfangen. Die Schnittstelle hat die folgenden Methoden:

IAnnouncementListener
Beschreibung: Wird immer dann gerufen, wenn sich die Ansageliste geändert hat.
HIDL2.0 oneway onListUpdated(vec<Announcement> announcements)
AIDL oneway void onListUpdated(in Announcement[] announcements)
Griff schließen

ICloseHandle ist das generische Close-Handle zum Entfernen eines Rückrufs, der keine aktive Schnittstelle benötigt.

ICloseHandle
Beschreibung: Schließen Sie den Griff.
HIDL2.0 close()
AIDL void close()

Callback-Schnittstelle

ITunerCallback ist die Rückrufschnittstelle, die von der Rundfunk-HAL aufgerufen wird, um Aktualisierungen an den HAL-Clientdienst zu senden.

ITunerCallback
Beschreibung: Wird von der HAL aufgerufen, wenn ein Tuning-Vorgang (tune, seek (in AIDL) oder scan (in HIDL) und Step erfolgreich) asynchron fehlschlägt.
HIDL2.0 oneway onCurrentProgramInfoChanged(ProgramInfo info)
AIDL void onCurrentProgramInfoChanged(in ProgramInfo info)
Beschreibung: Wird aufgerufen, wenn tune, seek (in AIDL) oder scan (in HIDL) oder step erfolgreich sind.
HIDL2.0 oneway onTuneFailed(Result result, ProgramSelector selector)
AIDL void onTuneFailed(in Result result, in ProgramSelector selector)
Beschreibung: Wird aufgerufen, wenn tune, seek (in AIDL) oder scan (in HIDL) oder step erfolgreich sind.
HIDL2.0 oneway onCurrentProgramInfoChanged(ProgramInfo info)
AIDL void onCurrentProgramInfoChanged(in ProgramInfo info)
Beschreibung: Wird aufgerufen, wenn die Programmliste aktualisiert wird; Die Größe jedes Chunks sollte auf 500 KB begrenzt sein.
HIDL2.0 oneway onProgramListUpdated(ProgramListChunk chunk)
AIDL oneway onProgramListUpdated(ProgramListChunk chunk)
Beschreibung: Wird aufgerufen, wenn die Antenne angeschlossen oder getrennt wird.
HIDL2.0 oneway onAntennaStateChange(bool connected)
AIDL void onCurrentProgramInfoChanged(in ProgramInfo info)
Beschreibung: Wird aufgerufen, wenn die herstellerspezifischen Parameterwerte intern in HAL aktualisiert werden (sollte nicht nach dem Aufruf von setParameters durch den HAL-Client aufgerufen werden).
HIDL2.0 oneway onParametersUpdated(vec<VendorKeyValue> parameters)
AIDL void onParametersUpdated(in VendorKeyValue[] parameters)
Beschreibung: Neu in AIDL. Wird aufgerufen, wenn das Konfigurations-Flag intern in der HAL aktualisiert wird (sollte nicht nach dem Aufruf von setConfigFlag durch den HAL-Client aufgerufen werden).
HIDL2.0 Unzutreffend.
AIDL void onConfigFlagUpdated(in ConfigFlag flag, in boolean value)

Primäre Rundfunk-HAL-Schnittstelle

IBroadcastRadio ist die primäre Schnittstelle für den Rundfunksender HAL. Verwenden Sie in der HIDL 2.0 HAL die ITunerSession Schnittstelle zum Tuner, um Vorgänge aufzurufen. Es ist jedoch höchstens ein Tuner gleichzeitig aktiv (vorausgesetzt, jede Rundfunk-HAL-Instanz hat nur einen Tuner-Chip). ITunerSession wurde aus den AIDL-Schnittstellen entfernt und seine Schnittstellen zu IBroadcastRadio .

IBroadcastRadio
Beschreibung: Rufen Sie die Beschreibung eines Moduls und seiner Fähigkeiten ab.
HIDL2.0 getProperties() generates (Properties properties)
AIDL Properties getProperties()
Beschreibung: Ruft die aktuelle oder mögliche AM/FM-Regionskonfiguration ab.
HIDL2.0 getAmFmRegionConfig(bool full) generates (Result result, AmFmRegionConfig config)
AIDL AmFmRegionConfig getAmFmRegionConfig(bool full)
Beschreibung: Ruft die aktuelle Konfiguration der DAB-Region ab.
HIDL2.0 getDabRegionConfig() generates (Result result, vec<DabTableEntry> config)
AIDL DabTableEntry[] getDabRegionConfig()
Beschreibung: Ruft ein Bild aus dem Funkmodul-Cache ab. In AIDL muss die Bildgröße aufgrund einer festen Begrenzung des Binder-Transaktionspuffers weniger als 1 MB betragen.
HIDL2.0 getImage(uint32_t id) generates (vec<uint8_t> image)
AIDL byte[] getImage(in int id)
Beschreibung: Registriert den Ansage-Listener.
HIDL2.0 registerAnnouncementListener(vec<AnnouncementType> enabled,IAnnouncementListener listener) generates (Result result, ICloseHandle closeHandle)
AIDL ICloseHandle registerAnnouncementListener(in IAnnouncementListener listener, in AnnouncementType[] enabled)
Beschreibung:
  • HIDL HAL: Wenn eine neue Tuner-Session geöffnet wird, muss die alte Session beendet werden.
  • AIDL HAL: Da keine Tuner-Session verfügbar ist, muss nur der Tuner-Callback gesetzt werden. Wenn es vorhanden ist, sollte der alte Rückruf deaktiviert werden.
HIDL2.0 openSession(ITunerCallback callback) generiert (Result result, ITunerSession session)
AIDL void setTunerCallback(in ITunerCallback callback)
Beschreibung:
  • HIDL HAL: Das Schließen einer Tuner-Session darf nicht fehlschlagen und darf nur einmal ausgegeben werden.
  • AIDL HAL: Es gibt keinen Tuner und nur der Tuner-Callback muss deaktiviert werden.
HIDL2.0 close()
AIDL unsetTunerCallback()
Beschreibung: Stellt auf ein bestimmtes Programm ein.
HIDL2.0 tune(ProgramSelector program) generates (Result result)
AIDL void tune(in ProgramSelector program)
Beschreibung: Sucht das nächste gültige Programm auf Sendung . Um Verwirrung in AIDL zu vermeiden, wird scan in seek umbenannt.
HIDL2.0 scan(bool directionUp, bool skipSubChannel) generates (Result result)
AIDL void seek(in boolean directionUp, in boolean skipSubChannel)
Beschreibung: Sprung zum Nachbarkanal, der von keinem Programm belegt sein darf.
HIDL2.0 step(bool directionUp) generates (Result result)
AIDL void step(in boolean directionUp)
Beschreibung: Bricht anstehende Tune-, Scan- (in HIDL) oder Seek- (in AIDL) oder Step-Operationen ab.
HIDL2.0 cancel()
AIDL void cancel()
Beschreibung: Wendet einen Filter auf die Programmliste an und beginnt mit dem Senden von Programmlistenaktualisierungen über den onProgramListUpdated Callback.
HIDL2.0 startProgramListUpdates(ProgramFilter filter) generates (Result result)
AIDL void startProgramListUpdates(in ProgramFilter filter)
Beschreibung: Stoppt das Senden von Aktualisierungen der Programmliste.
HIDL2.0 stopProgramListUpdates()
AIDL void stopProgramListUpdates()
Beschreibung: Ruft die aktuelle Einstellung eines bestimmten Konfigurationsflags ab.
HIDL2.0 isConfigFlagSet(ConfigFlag flag) generates (Result result, bool value)
AIDL boolean isConfigFlagSet(in ConfigFlag flag)
Beschreibung: Setzt das angegebene Konfigurationsflag.
HIDL2.0 setConfigFlag(ConfigFlag flag, bool value) generates (Result result)
AIDL void setConfigFlag(in ConfigFlag flag, boolean value)
Beschreibung: Legt herstellerspezifische Parameterwerte fest.
HIDL2.0 setParameters(vec<VendorKeyValue> parameters)

erzeugt ,

(vec<VendorKeyValue> results)
AIDL VendorKeyValue[] setParameters(in VendorKeyValue[] parameters)
Beschreibung: Ruft herstellerspezifische Parameterwerte ab.
HIDL2.0 getParameters(vec<string> keys) generates (vec<VendorKeyValue> parameters)
AIDL VendorKeyValue[] getParameters(in String[] keys)

Erläuterungen zur Schnittstelle

Asynchrones Verhalten

Da jeder Optimierungsvorgang (z. B. Tune, Scan (in HIDL) oder Seek (in AIDL) und Schritt) zeitaufwändig sein kann und der Thread nicht für längere Zeit blockiert werden sollte, sollte der Vorgang zeitaufwändige Vorgänge planen später auftreten und schnell einen Status oder ein Ergebnis zurückgeben. Im Einzelnen sollte jede Operation:

  • Brechen Sie alle ausstehenden Tuning-Vorgänge ab.
  • Überprüfen Sie, ob die Operation basierend auf den Methodeneingaben und dem Status des Tuners verarbeitet werden kann.
  • Planen Sie die Optimierungsaufgabe und geben Sie dann sofort das Result (in HIDL) oder den status (in AIDL) zurück. Wenn das Result oder der status OK ist, muss der Tuner-Callback tuneFailed oder currentProgramInfoChanged aufgerufen werden, wenn die Optimierungsaufgabe fehlgeschlagen ist (z. B. aufgrund einer Zeitüberschreitung) oder abgeschlossen ist.

In ähnlicher Weise startProgramListUpdates auch die zeitaufwändige Aufgabe, die Programmliste zu aktualisieren, um sie später auszuführen und schnell einen Status oder ein Ergebnis zurückzugeben. Das Verfahren bricht zuerst anstehende Aktualisierungsanforderungen ab und plant dann die Aktualisierungsaufgabe und gibt das Ergebnis schnell zurück.

Rennbedingung

Aufgrund des asynchronen Verhaltens von Tuning-Operationen (z. B. tune, scan (in HIDL) oder seek (in AIDL) und step) besteht eine Wettlaufbedingung zwischen dem Abbrechen der Operation und den Tuning-Operationen. Wenn cancel aufgerufen wird, nachdem die HAL einen Abstimmungsvorgang abgeschlossen hat und bevor der Rückruf abgeschlossen ist, kann der Abbruch ignoriert werden und der Rückruf sollte abgeschlossen und vom HAL-Client empfangen werden.

Wenn stopProgramListUpdates aufgerufen wird, nachdem die HAL eine Programmlistenaktualisierung abgeschlossen hat und bevor der onCurrentProgramInfoChanged Rückruf abgeschlossen ist, kann stopProgramListUpdates ignoriert werden und der Rückruf sollte abgeschlossen werden.

Begrenzung der Datengröße

Da es eine feste Grenze für den Binder-Transaktionspuffer gibt, wird die Datengrenze für einige Schnittstellenmethoden, die Daten mit einer potenziell großen Größe übergeben, in der AIDL HAL geklärt.

  • getImage erfordert, dass das zurückgegebene Bild weniger als 1 MB groß ist.
  • onProgramListUpdate erfordert, dass jeder chunk kleiner als 500 KB ist. Größere Programmlisten müssen von der HAL-Implementierung in mehrere Blöcke aufgeteilt und durch mehrere Rückrufe gesendet werden.

Änderungen in AIDL HAL-Datenstrukturen

Zusätzlich zu den Änderungen in den Schnittstellen wurden diese Änderungen auf die Datenstrukturen angewendet, die in der Rundfunk-AIDL HAL definiert sind, die die Vorteile der AIDL nutzt.

  • Constant enum wird in AIDL entfernt und in IBroadcastRadio als const int definiert. Inzwischen wird ANTENNA_DISCONNECTED_TIMEOUT_MS in ANTENNA_STATE_CHANGE_TIMEOUT_MS umbenannt. Eine neue Konstante int TUNER_TIMEOUT_MS wird hinzugefügt. Alle Abstimmungs-, Such- und Schrittoperationen müssen innerhalb dieser Zeit abgeschlossen sein.
  • Enum RDS und Deemphasis werden in Deemphasis entfernt und in AmFmRegionConfig als const int definiert. Dementsprechend werden sowohl fmDeemphasis als fmRds in ProgramInfo als int deklariert, ein Bit-Berechnungsergebnis der jeweiligen Flags. In der Zwischenzeit werden D50 und D75 in DEEMPHASIS_D50 bzw. DEEMPHASIS_D75 umbenannt.
  • Enum ProgramInfoFlags werden in AIDL entfernt und in ProgramInfo als const int mit einem hinzugefügten Präfix FLAG_ definiert. Entsprechend werden infoFlags in ProgramInfo als int deklariert, ein Bit-Berechnungsergebnis von Flags. TUNED wurde auch in FLAG_TUNABLE umbenannt, um besser zu beschreiben, wie der Sender eingestellt werden kann.
  • In AmFmBandRange wird scanSpacing in seekSpacing umbenannt, da scan in AIDL in seek umbenannt wurde.
  • Da das Union -Konzept in AIDL eingeführt wurde, werden MetadataKey und Metadata , die in HIDL HAL definiert sind, nicht mehr verwendet. In AIDL HAL sind AIDL-Union- Metadata definiert. Jeder Aufzählungswert, der zuvor in MetadataKey enthalten war, ist jetzt ein Feld in Metadata mit dem Typ string oder int, je nach Definition.

Implementierung der Funksteuerung

Die Implementierung der Radiosteuerung basiert auf MediaSession und MediaBrowse , die es Medien- und Sprachassistenten-Apps ermöglichen, das Radio zu steuern. Weitere Informationen finden Sie unter Erstellen von Medien-Apps für Autos auf developer.android.com.

Eine Medienbaum-Implementierung wird in der car-broadcastradio-support-Bibliothek in packages/apps/Car/libs bereitgestellt. Diese Bibliothek enthält auch Erweiterungen von ProgramSelector zum Konvertieren in und aus URI. Es wird empfohlen, dass Funkimplementierungen diese Bibliothek verwenden, um den zugehörigen Suchbaum zu erstellen.

Umschalter für Medienquellen

Um einen nahtlosen Übergang zwischen Radio und anderen in Medien angezeigten Apps bereitzustellen, enthält die Car-Media-Common-Bibliothek Klassen, die in die Radio-App integriert werden sollten. MediaAppSelectorWidget kann in das XML für die Radio-App aufgenommen werden (das Symbol und die Dropdown-Liste, die in den Referenzmedien und Radio-Apps verwendet werden):

<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" />

Dieses Widget startet das AppSelectionFragment , das eine Liste von Medienquellen anzeigt, zu denen gewechselt werden kann. Wenn eine andere als die bereitgestellte Benutzeroberfläche gewünscht wird, können Sie ein benutzerdefiniertes Widget erstellen, um das AppSelectionFragment zu starten, wenn der Umschalter angezeigt werden soll.

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

Eine Beispielimplementierung wird in der Referenz-Radio-App-Implementierung bereitgestellt, die sich in packages/apps/Car/Radio befindet.

Detaillierte Steuerungsspezifikationen

Die Schnittstelle MediaSession (über MediaSession.Callback ) bietet Kontrollmechanismen für das aktuell laufende Radioprogramm:

  • onPlay , onStop . Radiowiedergabe (auf)stumm schalten.
  • onPause . Zeitversetzte Pause (sofern unterstützt).
  • onPlayFromMediaId . Spielen Sie beliebige Inhalte aus einem Ordner der obersten Ebene ab. Beispiel: „FM abspielen“ oder „Radio abspielen“.
  • onPlayFromUri . Spielen Sie eine bestimmte Frequenz. Beispiel: „Spiele 88,5 FM“.
  • onSkipToNext , onSkipToPrevious . Stellen Sie einen nächsten oder vorherigen Sender ein.
  • onSetRating . Hinzufügen oder Entfernen zu oder aus Favoriten.

Der MediaBrowser stellt ein einstellbares MediaItem über drei Arten von Verzeichnissen der obersten Ebene bereit:

  • ( Optional ) Programme (Stationen). Dieser Modus wird typischerweise von Dual-Tuner-Funkgeräten verwendet, um alle verfügbaren abstimmbaren Radiosender am Standort des Benutzers anzuzeigen.
  • Favoriten. Radioprogramme, die der Favoritenliste hinzugefügt wurden, sind möglicherweise nicht verfügbar (außerhalb des Empfangsbereichs).
  • Bandkanäle. Alle physikalisch möglichen Kanäle in der aktuellen Region (87.9, 88.1, 88.3, ​​88.5, 88.7, 88.9, 89.1 usw.). Jede Band hat ein separates Top-Level-Verzeichnis.
MediaBrowserService-Baumstruktur
Abbildung 2. MediaBrowserService-Baumstruktur

Jedes Element in jedem dieser Ordner (AM/FM/Programs) ist ein MediaItem mit einer URI, die mit MediaSession zum Tunen verwendet werden kann. Jeder Ordner der obersten Ebene (AM/FM/Programme) ist ein MediaItem mit einer mediaId, die mit MediaSession zum Auslösen der Wiedergabe verwendet werden kann und im Ermessen des OEM liegt. Beispielsweise sind „FM abspielen“, „AM abspielen“ und „Radio abspielen“ alles unspezifische Radioabfragen, die eine mediaId zum Senden an die OEM-Radio-App verwenden. Es liegt an der Radio-App, anhand der generischen Anfrage und der mediaId zu bestimmen, was wiedergegeben werden soll.

Mediensitzung

Da es kein Konzept zum Anhalten eines Broadcast-Streams gibt, gelten die Aktionen Play, Pause und Stop nicht immer für Radio. Beim Radio ist die Stop-Aktion mit dem Stummschalten des Streams verbunden, während Play mit dem Aufheben der Stummschaltung verbunden ist.

Einige Radiotuner (oder Apps) bieten die Möglichkeit, eine Unterbrechung des Sendestroms zu simulieren, indem Inhalte zwischengespeichert und später wiedergegeben werden. Verwenden Sie in solchen Fällen onPause .

Das Abspielen von mediaId- und URI-Aktionen dient dazu, einen Sender einzustellen, der von der MediaBrowser-Schnittstelle abgerufen wird. Die mediaId ist eine willkürliche Zeichenfolge, die von der Radio-App bereitgestellt wird, um einen eindeutigen (so dass eine bestimmte ID auf nur ein Element zeigt) und stabilen Wert (so dass ein bestimmtes Element während der gesamten Sitzung dieselbe ID hat) aufzuerlegen, mit dem ein bestimmter Sender identifiziert werden kann . Der URI hat ein wohldefiniertes Schema. Kurz gesagt, eine URI-isierte Form von ProgramSelector. Während dies das Eindeutigkeitsattribut bewahrt, muss es nicht stabil sein, obwohl es sich ändern kann, wenn sich die Station auf eine andere Frequenz bewegt.

onPlayFromSearch wird standardmäßig nicht verwendet. Es liegt in der Verantwortung des Clients (Begleit-App), ein Suchergebnis aus der MediaBrowser-Struktur auszuwählen. Die Übertragung dieser Verantwortung auf die Radio-App würde die Komplexität erhöhen, formelle Verträge darüber erfordern, wie Zeichenfolgenabfragen angezeigt werden sollen, und zu einer uneinheitlichen Benutzererfahrung auf verschiedenen Hardwareplattformen führen.

Hinweis: Die Radio-App enthält keine zusätzlichen Informationen, die nützlich wären, um nach einem Sendernamen zu suchen, der dem Client nicht über die MediaBrowser-Schnittstelle angezeigt wird.

Das Springen zum nächsten oder vorherigen Sender hängt vom aktuellen Kontext ab:

  • Wenn eine App auf einen Sender aus der Favoritenliste eingestellt ist, kann die App zum nächsten Sender aus der Favoritenliste wechseln.
  • Das Hören eines Senders aus der Programmliste kann dazu führen, dass der nächste verfügbare Sender eingestellt wird, sortiert nach der Kanalnummer.
  • Das Hören eines beliebigen Kanals kann dazu führen, dass auf den nächsten physikalischen Kanal umgeschaltet wird, selbst wenn kein Sendesignal vorhanden ist.

Die Radio-App verarbeitet diese Aktionen.

Fehlerbehandlung

TransportControls Aktionen (Play, Stop und Next) geben kein Feedback darüber, ob die Aktion erfolgreich war oder nicht. Die einzige Möglichkeit, einen Fehler anzuzeigen, besteht darin, den MediaSession-Status mit einer Fehlermeldung auf STATE_ERROR zu setzen.

Die Radio-App muss diese Aktionen verarbeiten und sie entweder ausführen oder einen Fehlerzustand festlegen. Wenn die Ausführung des Play-Befehls nicht sofort erfolgt, sollte der Wiedergabezustand auf STATE_CONNECTING (bei direkter Abstimmung) oder STATE_SKIPPING_TO_PREVIOUS oder NEXT geändert werden, während der Befehl ausgeführt wird.

Der Client sollte den PlaybackState überwachen und überprüfen, ob die Sitzung das aktuelle Programm in das angeforderte geändert oder in den Fehlerstatus versetzt hat. STATE_CONNECTING darf 30 Sekunden nicht überschreiten. Eine direkte Abstimmung auf eine bestimmte AM/FM-Frequenz sollte jedoch viel schneller ablaufen.

Hinzufügen und Entfernen von Favoriten

MediaSession bietet Bewertungsunterstützung, die zur Steuerung von Favoriten verwendet werden kann. onSetRating , das mit einer Bewertung vom Typ RATING_HEART fügt den aktuell eingestellten Sender zu oder aus der Favoritenliste hinzu oder entfernt ihn.

Im Gegensatz zu älteren Voreinstellungen geht dieses Modell von einer ungeordneten und unbegrenzten Favoritenliste aus, wenn jeder gespeicherte Favorit einem numerischen Platz (typischerweise 1 bis 6) zugeordnet wurde. Infolgedessen wären voreingestellte Systeme mit onSetRating -Betrieb inkompatibel.

Die Einschränkung der MediaSession-API besteht darin, dass nur der aktuell eingestellte Sender hinzugefügt oder entfernt werden kann. Beispielsweise müssen Elemente zuerst ausgewählt werden, bevor sie entfernt werden können. Dies ist nur eine Einschränkung des MediaBrowser-Clients, z. B. einer Begleit-App. Die Radio-App ist nicht ähnlich eingeschränkt. Dieser Teil ist optional, wenn eine App Favoriten nicht unterstützt.

MediaBrowser

Um auszudrücken, welche Frequenzen oder physikalischen Kanalnamen (wenn das Einstellen auf einen beliebigen Kanal für eine bestimmte Funktechnologie geeignet ist) für eine bestimmte Region gültig sind, werden alle gültigen Kanäle (Frequenzen) für jedes Band aufgelistet. In der US-Region beläuft sich dies auf 101 FM-Kanäle im Bereich von 87,8 bis 108,0 MHz (unter Verwendung eines Abstands von 0,2 MHz) und 117 AM-Kanäle im Bereich von 530 bis 1700 kHz (unter Verwendung eines Abstands von 10 kHz). Da HD-Radio denselben Kanalraum verwendet, wird es nicht separat dargestellt.

Die Liste der derzeit verfügbaren Radioprogramme ist dahingehend flach, dass dies keine Anzeigeschemata zulässt, wie beispielsweise eine Gruppierung nach DAB-Ensemble (Direct Audio Broadcast).

Einträge in der Favoritenliste sind möglicherweise nicht abstimmbar. Zum Beispiel, wenn ein bestimmtes Programm außerhalb des Bereichs liegt. Die Radio-App kann vorher erkennen, ob der Eintrag eingestellt werden kann oder nicht. Wenn dies der Fall ist, wird der Eintrag möglicherweise nicht als spielbar markiert.

Um Ordner der obersten Ebene zu identifizieren, wird derselbe Mechanismus angewendet, der von Bluetooth verwendet wird. Das heißt, ein Extras-Bundle des MediaDescription -Objekts enthält ein tunerspezifisches Feld, genau wie Bluetooth es mit EXTRA_BT_FOLDER_TYPE . Im Falle des Rundfunks führt dies zur Definition der folgenden neuen Felder in der öffentlichen API:

  • EXTRA_BCRADIO_FOLDER_TYPE = "android.media.extra.EXTRA_BCRADIO_FOLDER_TYPE" . Einer der folgenden Werte:
    • BCRADIO_FOLDER_TYPE_PROGRAMS = 1 . Aktuell verfügbare Programme.
    • BCRADIO_FOLDER_TYPE_FAVORITES = 2 . Favoriten.
    • BCRADIO_FOLDER_TYPE_BAND = 3 . Alle physischen Kanäle für ein bestimmtes Band.

    Es ist nicht erforderlich, radiospezifische benutzerdefinierte Metadatenfelder zu definieren, da alle relevanten Daten in das vorhandene MediaBrowser.MediaItem Schema passen:

    • Programmname (RDS PS, DAB-Dienstname). MediaDescription.getTitle .
    • UKW-Frequenz. URI (siehe ProgramSelector ) oder MediaDescription.getTitle (wenn sich ein Eintrag im Ordner BROADCASTRADIO_FOLDER_TYPE_BAND befindet).
    • Radiospezifische Kennungen (RDS PI, DAB SId). MediaDescription.getMediaUri in ProgramSelector geparst.

    Typischerweise besteht keine Notwendigkeit, die UKW-Frequenz für einen Eintrag im aktuellen Programm oder in der Favoritenliste abzurufen (da der Client mit Medien-IDs arbeiten sollte). Sollte jedoch ein solcher Bedarf entstehen (z. B. zu Anzeigezwecken), ist er in der URI vorhanden und kann in ProgramSelector geparst werden. Es wird jedoch nicht empfohlen, den URI zum Auswählen von Elementen in der aktuellen Sitzung zu verwenden. Einzelheiten finden Sie unter ProgramSelector .

    Um Leistungs- oder Binder-bezogene Probleme zu vermeiden, muss der MediaBrowser-Dienst Paginierung unterstützen:

    Hinweis: Standardmäßig wird die Paginierung standardmäßig in der Variante onLoadChildren() ohne Optionenbehandlung implementiert.

    Verwandte Einträge aus allen Arten von Listen (Rohkanäle, gefundene Programme und Favoriten) können unterschiedliche mediaIds haben (es liegt an der Radio-App; die Support-Bibliothek wird sie unterschiedlich haben). Die URIs (in ProgramSelector-Form) unterscheiden sich in den meisten Fällen zwischen Rohkanälen und gefundenen Programmen (außer bei FM ohne RDS), sind aber zwischen gefundenen Programmen und Favoriten meistens gleich (außer zum Beispiel, wenn AF aktualisiert wurde).

    Durch unterschiedliche mediaIds für Einträge aus unterschiedlichen Listentypen können unterschiedliche Aktionen mit ihnen durchgeführt werden. Sie können entweder die Favoritenliste oder die Liste Alle Programme auf onSkipToNext , je nach Ordner des zuletzt ausgewählten MediaItem (siehe MediaSession ).

    Spezielle Tune-Aktionen

    Die Programmliste ermöglicht es Benutzern, auf einen bestimmten Sender abzustimmen, erlaubt Benutzern jedoch nicht, allgemeine Anfragen wie "Auf FM einstellen" zu stellen, was dazu führen könnte, dass auf einen kürzlich gehörten Sender auf dem FM-Band eingestellt wird.

    Um solche Aktionen zu unterstützen, haben einige Verzeichnisse der obersten Ebene das Flag FLAG_PLAYABLE gesetzt (zusammen mit FLAG_BROWSABLE für Ordner).

    Handlung Stimmt zu Wie ausstellen
    Radio spielen Jeder Funkkanal startService(ACTION_PLAY_BROADCASTRADIO)

    oder,

    playFromMediaId(MediaBrowser. getRoot() )
    FM abspielen Jeder UKW-Kanal Spielen Sie von der mediaId des UKW-Bands ab.

    Die Bestimmung, welches Programm eingestellt werden soll, liegt bei der App. Dies ist normalerweise der zuletzt eingestellte Kanal aus der gegebenen Liste. Einzelheiten zu ACTION_PLAY_BROADCASTRADIO finden Sie unter Allgemeine Wiedergabeabsichten .

    Erkennung und Serviceverbindung

    PackageManager kann den MediaBrowserService, der den Broadcast-Radio-Baum bereitstellt, direkt finden. Rufen resolveService mit der Absicht ACTION_PLAY_BROADCASTRADIO (siehe Allgemeine Wiedergabeabsichten ) und dem Flag MATCH_SYSTEM_ONLY . Verwenden queryIntentServices , um alle Dienste zu finden, die Radio bereitstellen (es kann mehr als einen geben, z. B. separate AM/FM und Satellit).

    Der aufgelöste Dienst verarbeitet auch die android.media.browse.MediaBrowserService . Dies wird mit GTS verifiziert.

    Um eine Verbindung mit dem ausgewählten MediaBrowserService herzustellen, erstellen Sie eine MediaBrowser Instanz für eine bestimmte Dienstkomponente und connect Sie . Nach dem Verbindungsaufbau kann über getSessionToken ein Handle auf MediaSession bezogen werden.

    Die Radio-App kann Client-Pakete einschränken, die in einer onGetRoot -Implementierung ihres Dienstes eine Verbindung herstellen dürfen. Die App sollte es System-Apps ermöglichen, sich ohne Whitelist zu verbinden. Weitere Informationen zum Whitelisting finden Sie unter Paket und Signatur der Assistant-App akzeptieren .

    Wenn die quellenspezifische App (z. B. eine Radio-App) auf einem Gerät ohne eine solche Quellenunterstützung installiert ist, würde sie sich immer noch so ausgeben, dass sie die Absicht ACTION_PLAY_BROADCASTRADIO , aber ihre MediaBrowser-Struktur würde keine radiospezifischen Tags enthalten. Daher muss ein Client, der prüfen möchte, ob eine bestimmte Quelle auf einem Gerät verfügbar ist, Folgendes tun:

    1. Entdecken Sie den Radiodienst (rufen resolveService für ACTION_PLAY_BROADCASTRADIO auf).
    2. Erstellen Sie MediaBrowser und stellen Sie dann eine Verbindung her.
    3. Bestimmen Sie das Vorhandensein von MediaItem mit EXTRA_BCRADIO_FOLDER_TYPE extra.

    Hinweis: In den meisten Fällen muss der Client alle verfügbaren MediaBrowser-Bäume scannen, um alle verfügbaren Quellen für ein bestimmtes Gerät zu erkennen.

    Bandnamen

    Die Bandliste wird durch eine Reihe von Verzeichnissen der obersten Ebene mit einem Ordnertyp-Tag dargestellt, das auf BCRADIO_FOLDER_TYPE_BAND . Die Titel ihrer MediaItem sind lokalisierte Zeichenfolgen, die Bandnamen darstellen. In den meisten Fällen wird es sich um eine englische Übersetzung handeln, aber der Kunde kann sich nicht darauf verlassen.

    Um einen stabilen Mechanismus zum Suchen bestimmter Bands bereitzustellen, wird ein zusätzliches Tag für Bandordner hinzugefügt, EXTRA_BCRADIO_BAND_NAME_EN . Dies ist ein nicht lokalisierter Name der Band und kann nur einen dieser vordefinierten Werte annehmen:

    • AM
    • FM
    • DAB

    Wenn sich die Band nicht auf dieser Liste befindet, sollte das Bandnamen-Tag nicht gesetzt werden. Wenn sich die Band jedoch auf der Liste befindet, muss für sie ein Tag festgelegt sein. HD-Radio zählt keine separaten Bänder auf, da es dasselbe zugrunde liegende Medium wie AM/FM verwendet.

    Allgemeine Spielabsichten

    Jede App, die für die Wiedergabe einer bestimmten Quelle (wie Radio oder CD) bestimmt ist, muss eine allgemeine Wiedergabeabsicht verarbeiten, um mit der Wiedergabe von Inhalten zu beginnen, möglicherweise aus einem inaktiven Zustand (z. B. nach dem Booten). Es liegt an der App, wie sie den abzuspielenden Inhalt auswählt, aber in der Regel handelt es sich um das zuletzt abgespielte Radioprogramm oder den CD-Titel. Für jede Audioquelle ist ein separater Intent definiert:

    • android.car.intent.action.PLAY_BROADCASTRADIO
    • android.car.intent.action.PLAY_AUDIOCD : CD-DA oder CD-Text
    • android.car.intent.action.PLAY_DATADISC : Optische Datendisc wie CD/DVD, aber keine CD-DA (möglicherweise Mixed-Mode-CD)
    • android.car.intent.action.PLAY_AUX : Ohne Angabe des AUX-Ports
    • android.car.intent.action.PLAY_BLUETOOTH
    • android.car.intent.action.PLAY_USB : Ohne Angabe des USB-Geräts
    • android.car.intent.action.PLAY_LOCAL : Lokaler Medienspeicher (integrierter Flash)

    Absichten wurden ausgewählt, um für allgemeine Wiedergabebefehle verwendet zu werden, da sie zwei Probleme gleichzeitig lösen: den allgemeinen Wiedergabebefehl selbst und die Diensterkennung. Ein zusätzlicher Vorteil einer solchen Absicht wäre die Möglichkeit, eine solche einfache Aktion auszuführen, ohne eine MediaBrowser-Sitzung zu öffnen.

    Service Discovery ist eigentlich das wichtigere Problem, das mit diesen Absichten gelöst wird. Das Verfahren zur Diensterkennung ist auf diese Weise einfach und eindeutig (siehe Erkennung und Dienstverbindung ).

    Um einige Client-Implementierungen zu vereinfachen, gibt es eine alternative Möglichkeit, einen solchen Play-Befehl auszugeben (der auch von der Radio-App implementiert werden muss): Ausgeben von playFromMediaId mit der rootId des Root-Knotens (als mediaId verwendet). Während der Root-Knoten nicht abspielbar sein soll, ist seine rootId eine beliebige Zeichenfolge, die als mediaId konsumierbar gemacht werden kann. Kunden müssen diese Nuance jedoch nicht verstehen.

    ProgramSelector

    Während mediaId ausreicht, um einen Kanal aus dem MediaBrowserService , wird es an eine Sitzung gebunden und zwischen den Anbietern nicht konsistent. In einigen Fällen benötigt der Client möglicherweise einen absoluten Zeiger (z. B. eine absolute Häufigkeit), um ihn zwischen Sitzungen und Geräten beizubehalten.

    Im Zeitalter digitaler Radiosendungen reicht eine reine Frequenz nicht aus, um einen bestimmten Sender einzustellen. Stellen Sie daher mit ProgramSelector einen analogen oder digitalen Kanal ein. ProgramSelector besteht aus zwei Teilen:

    • Primäre Kennung. Eine eindeutige und stabile Kennung für einen bestimmten Radiosender, die sich nicht ändert, aber möglicherweise nicht ausreicht, um diesen Sender einzustellen. Zum Beispiel RDS PI-Code, der in den USA in das Rufzeichen übersetzt werden kann.
    • Sekundäre Identifikatoren. Zusätzliche Identifikatoren, die zum Einstellen auf diesen Sender nützlich sind (z. B. Frequenz), möglicherweise einschließlich Identifikatoren von anderen Funktechnologien. Beispielsweise kann ein DAB-Sender einen analogen Rundfunk-Fallback haben.

    Damit ProgramSelector in die MediaBrowser oder MediaSession basierte Lösung passt, definieren Sie ein URI-Schema, um es zu serialisieren. Das Schema ist wie folgt definiert:

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

    In diesem Beispiel ist der sekundäre Bezeichner-Teil (nach dem Fragezeichen ( ? )) optional und kann entfernt werden, um einen stabilen Bezeichner zur Verwendung als mediaId . Zum Beispiel:

    • 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

    Der Behördenteil (AKA-Host) des program bietet Raum für zukünftige Systemerweiterungen. Die Zeichenfolgen des Bezeichnertyps werden genau als ihre Namen in der HAL 2.x-Definition von IdentifierType angegeben, und das Wertformat ist eine Dezimal- oder Hexadezimalzahl (mit 0x -Präfix).

    Alle herstellerspezifischen Bezeichner werden durch das Präfix VENDOR_ . Beispiel: VENDOR_0 für VENDOR_START und VENDOR_1 für VENDOR_START plus 1. Solche URIs sind spezifisch für die Funkhardware, auf der sie generiert wurden, und können nicht zwischen Geräten verschiedener OEMs übertragen werden.

    Diese URIs müssen jedem MediaItem unter den Radioordnern der obersten Ebene zugewiesen werden. Darüber hinaus muss die MediaSession sowohl playFromMediaId als auch playFromUri . Der URI ist jedoch in erster Linie für die Extraktion von Radiometadaten (z. B. FM-Frequenz) und die dauerhafte Speicherung vorgesehen. Es gibt keine Garantie, dass der URI für alle Medienelemente verfügbar ist (z. B. wenn der primäre ID-Typ noch nicht vom Framework unterstützt wird). Andererseits funktioniert Media ID immer. Es wird nicht empfohlen , dass Clients URI verwenden, um Elemente aus der aktuellen MediaBrowser-Sitzung auszuwählen. Verwenden Sie stattdessen playFromMediaId . Allerdings ist es für die Serving-App nicht optional, und fehlende URIs sind für gut begründete Fälle reserviert.

    Das ursprüngliche Design verwendete einen einzelnen Doppelpunkt anstelle der :// Sequenz nach dem Schemateil. Ersteres wird jedoch von android.net.Uri für absolute hierarchische URI-Referenzen nicht unterstützt.

    Andere Quelltypen

    Andere Audioquellen können ähnlich gehandhabt werden. Zum Beispiel AUX-Eingang und der Audio-CD-Player.

    Eine einzelne App kann mehrere Arten von Quellen bedienen. In solchen Fällen wird empfohlen , für jeden Quellentyp einen separaten MediaBrowserService zu erstellen. Selbst in einer Einrichtung mit mehreren bereitgestellten Quellen/MediaBrowserServices wird dringend empfohlen , eine einzelne MediaSession in einer einzelnen App zu haben.

    Audio-CD

    Ähnlich wie bei Audio-CDs würde die App, die solche Datenträger bereitstellt, MediaBrowser mit einem einzigen durchsuchbaren Eintrag (oder mehr, wenn das System über einen CD-Wechsler verfügt) verfügbar machen, der wiederum alle Titel einer bestimmten CD enthalten würde. Wenn das System die Tracks auf jeder CD nicht kennt (z. B. wenn alle Datenträger gleichzeitig in eine Kassette eingelegt sind und nicht alle gelesen werden), wäre MediaItem für den gesamten Datenträger nur PLAYABLE , nicht BROWSABLE plus PLAYABLE . Wenn sich in einem bestimmten Steckplatz keine Diskette befindet, wäre das Element weder PLAYABLE noch BROWSABLE (aber jeder Steckplatz muss immer im Baum vorhanden sein).

    Audio-CD-Baumstruktur
    Abbildung 3. Audio-CD-Baumstruktur

    Diese Einträge würden auf ähnliche Weise wie Rundfunkordner gekennzeichnet; Sie würden zusätzliche zusätzliche Felder enthalten, die in der MediaDescription-API definiert sind:

    • EXTRA_CD_TRACK : Für jedes MediaItem auf Audio-CD, 1-basierte Titelnummer.
    • EXTRA_CD_DISK : 1-basierte Plattennummer.

    Für ein CD-Text-fähiges System und eine kompatible Platte hätte das MediaItem der obersten Ebene einen Titel der Platte. In ähnlicher Weise würden die MediaItems für Tracks einen Titel des Tracks haben.

    AUX Eingang

    Die App, die Hilfseingaben bereitstellt, macht eine MediaBrowser-Struktur mit einem einzelnen Eintrag (oder mehreren, wenn mehrere Ports vorhanden sind) verfügbar, der den AUX-Eingangsport darstellt. Die jeweilige MediaSession nimmt ihre mediaId und wechselt zu dieser Quelle, nachdem sie die playFromMediaId Anforderung erhalten hat.

    AUX-Baumstruktur
    Abbildung 4. AUX-Baumstruktur

    Jeder AUX-MediaItem-Eintrag hätte ein zusätzliches Feld EXTRA_AUX_PORT_NAME , das auf den nicht lokalisierten Namen des Ports ohne die „AUX“-Phrase gesetzt ist. For example, "AUX 1" would have be set to "1", "AUX front" to "front" and "AUX" to an empty string. In non-English locales, the name tag would remain the same English string. Unlikely as for EXTRA_BCRADIO_BAND_NAME_EN , the values are OEM-defined and not constrained to a predefined list.

    If the hardware can detect devices connected to the AUX port, the hardware should mark the MediaItem as PLAYABLE , only if input is connected. The hardware should still be enumerated (but not PLAYABLE ) if nothing was connected to this port. If the hardware has no such capability, the MediaItem must always be set to PLAYABLE .

    Extra fields

    Define the following fields:

    • 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"

    Client needs to review the top-level MediaItems for elements having the EXTRA_CD_DISK or EXTRA_AUX_PORT_NAME extra field set.

    Detailed examples

    The following examples address the MediaBrowser tree structure for source types that are part of this design.

    Broadcast radio MediaBrowserService (handles ACTION_PLAY_BROADCASTRADIO ):

    • Stations (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 (playable) – FM without RDSURI: broadcastradio://program/AMFM_FREQUENCY/90500
      • 620 AM (playable) URI: broadcastradio://program/AMFM_FREQUENCY/620
      • BBC One (playable) URI: broadcastradio://program/DAB_SID_EXT/1E24102?RDS_PI=1234
    • Favorites (browsable, playable) EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_FAVORITES
      • BBC One (playable) URI: broadcastradio://program/RDS_PI/1234?AMFM_FREQUENCY=101300
      • BBC Two (not playable)URI: broadcastradio://program/RDS_PI/1300?AMFM_FREQUENCY=102100
    • AM (browsable, playable): EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BANDEXTRA_BCRADIO_BAND_NAME_EN="AM"
      • 530 AM (playable) 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 MediaBrowserService (handles ACTION_PLAY_AUDIOCD ):

    • Disc 1 (playable) EXTRA_CD_DISK=1
    • Disc 2 (browsable, playable) EXTRA_CD_DISK=2
      • Track 1 (playable) EXTRA_CD_TRACK=1
      • Track 2 (playable) EXTRA_CD_TRACK=2
    • My music CD (browsable, playable) EXTRA_CD_DISK=3
      • All By Myself (playable) EXTRA_CD_TRACK=1
      • Reise, Reise (playable) EXTRA_CD_TRACK=2
    • Empty slot 4 (not playable) EXTRA_CD_DISK=4

    AUX MediaBrowserService (handles ACTION_PLAY_AUX ):

    • AUX front (playable) EXTRA_AUX_PORT_NAME="front"
    • AUX rear (playable) EXTRA_AUX_PORT_NAME="rear"