Tuner-Framework

Bei Android 11 oder höher können Sie das Android Tuner-Framework verwenden, um A/V-Inhalte bereitzustellen. Das Framework verwendet die Hardware-Pipeline von Anbietern und eignet sich daher sowohl für Low-End- als auch für High-End-SoCs. Es bietet eine sichere Möglichkeit, A/V-Inhalte bereitzustellen, die durch eine Trusted Execution Environment (TEE) und einen Secure Media Path (SMP) geschützt sind. Dadurch kann es in einer stark eingeschränkten Umgebung mit Inhaltsschutz verwendet werden.

Die standardisierte Schnittstelle zwischen Tuner und Android CAS führt zu einer schnelleren Integration zwischen Tuner- und CAS-Anbietern. Die Tuner-Schnittstelle funktioniert mit MediaCodec und AudioTrack, um eine globale Lösung für Android TV zu entwickeln. Die Tuner-Schnittstelle unterstützt sowohl digitales als auch analoges Fernsehen auf Grundlage der wichtigsten Broadcast-Standards.

Komponenten

Für Android 11 wurden drei Komponenten speziell für die TV-Plattform entwickelt.

  • Tuner HAL:Eine Schnittstelle zwischen dem Framework und Anbietern
  • Tuner SDK API:Eine Schnittstelle zwischen dem Framework und Apps
  • Tuner Resource Manager (TRM): Koordiniert Tuner-Hardware-Ressourcen

In Android 11 wurden die folgenden Komponenten verbessert.

  • CAS V2
  • TvInputService oder TV Input Service (TIS)
  • TvInputManagerService oder TV Input Manager Service (TIMS)
  • MediaCodec oder Medien-Codec
  • AudioTrack oder Audiotrack
  • MediaResourceManager oder Media Resource Manager (MRM)

Flussdiagramm der Tuner-Framework-Komponenten.

Abbildung 1: Interaktionen zwischen Android TV-Komponenten

Funktionen

Das Frontend unterstützt die folgenden DTV-Standards.

  • ATSC
  • ATSC3
  • DVB C/S/T
  • ISDB S/S3/T
  • Analog

Das Frontend in Android 12 mit Tuner HAL 1.1 oder höher unterstützt den folgenden DTV-Standard.

  • DTMB

Demux unterstützt die folgenden Streamprotokolle.

  • Transport Stream (TS)
  • MPEG Media Transport Protocol (MMTP)
  • Internet Protocol (IP)
  • Typ-Längen-Wert (TLV)
  • ATSC Link-Layer Protocol (ALP)

Der Descrambler unterstützt die folgenden Inhaltsschutzmechanismen.

  • Sicherer Medienpfad
  • Medienpfad löschen
  • Lokale Aufzeichnung sichern
  • Sichere lokale Wiedergabe

Tuner APIs unterstützen die folgenden Anwendungsfälle.

  • Scannen
  • Live
  • Wiedergabe
  • Aufnehmen

Tuner, MediaCodec und AudioTrack unterstützen die folgenden Datenflussmodi.

  • ES-Nutzlast mit geleertem Arbeitsspeicherpuffer
  • ES-Payload mit Handle für sicheren Speicher
  • Passthrough

Design allgemein

Die Tuner-HAL wird zwischen dem Android-Framework und der Hardware des Anbieters definiert.

  • Beschreibt, was das Framework vom Anbieter erwartet und wie der Anbieter dies umsetzen kann.
  • Exportiert die Funktionen von Frontend, Demux und Descrambler über die Schnittstellen IFrontend, IDemux, IDescrambler, IFilter, IDvr und ILnb in das Framework.
  • Enthält die Funktionen zum Einbinden des Tuner HAL in andere Framework-Komponenten wie MediaCodec und AudioTrack.

Es werden eine Tuner-Java-Klasse und eine native Klasse erstellt.

  • Über die Tuner Java API können Apps über öffentliche APIs auf das Tuner HAL zugreifen.
  • Die native Klasse ermöglicht die Berechtigungssteuerung und die Verarbeitung großer Mengen an Aufzeichnungs- oder Wiedergabedaten mit dem Tuner HAL.
  • Das native Tuner-Modul ist eine Brücke zwischen der Tuner-Java-Klasse und dem Tuner-HAL.

Eine TRM-Klasse wird erstellt.

  • Verwaltet begrenzte Tuner-Ressourcen wie Frontend, LNB, CAS-Sitzungen und ein TV-Eingabegerät über den TV-Eingabe-HAL.
  • Wendet Regeln an, um unzureichende Ressourcen von Apps zurückzufordern. Die Standardregel ist der Vordergrundgewinn.

Media CAS und der CAS HAL werden durch die folgenden Funktionen erweitert.

  • Öffnet CAS-Sitzungen für verschiedene Verwendungszwecke und Algorithmen.
  • Unterstützt dynamische CAS-Systeme wie das Entfernen und Einsetzen von CICAMs.
  • Es wird in das Tuner-HAL eingebunden, indem es Schlüssel-Tokens bereitstellt.

MediaCodec und AudioTrack wurden um die folgenden Funktionen erweitert.

  • Nimmt sicheren A/V-Speicher als Inhaltseingabe.
  • Für die Hardware-A/V-Synchronisierung bei der Wiedergabe im Tunnel konfiguriert.
  • Unterstützung für ES_payload und den Passthrough-Modus wurde konfiguriert.

Gesamtdesign der Tuner HAL.

Abbildung 2: Diagramm der Komponenten in der Tuner-HAL

Gesamter Workflow

Die folgenden Diagramme veranschaulichen die Aufrufsequenzen für die Wiedergabe von Liveübertragungen.

Einrichten

Einrichtungsreihenfolge für das Wiedergabediagramm für Liveübertragungen.

Abbildung 3: Wiedergabereihenfolge für Live-Broadcasts einrichten

Umgang mit A/V

Diagramm zur Verarbeitung von Audio und Video für die Wiedergabe von Liveübertragungen.

Abbildung 4: Umgang mit A/V für die Wiedergabe von Liveübertragungen

Umgang mit verschlüsselten Inhalten

Diagramm zur Verarbeitung verschlüsselter Inhalte für die Wiedergabe von Live-Übertragungen

Abbildung 5: Umgang mit verschlüsselten Inhalten bei der Wiedergabe von Liveübertragungen

Verarbeitung von Audio- und Videodaten

Diagramm zur Verarbeitung von A/V-Daten für die Wiedergabe von Liveübertragungen

Abbildung 6 Verarbeitung von Audio und Video für die Wiedergabe von Liveübertragungen

Tuner SDK API

Die Tuner SDK API übernimmt die Interaktionen mit dem Tuner JNI, dem Tuner HAL und TunerResourceManager. Die TIS-App verwendet die Tuner SDK API, um auf Tuner-Ressourcen und ‑Unterkomponenten wie den Filter und den Descrambler zuzugreifen. Frontend und Demux sind interne Komponenten.

Ablaufdiagramm der Tuner SDK API.

Abbildung 7. Interaktionen mit der Tuner SDK API

Versionen

Ab Android 12 unterstützt die Tuner SDK API neue Funktionen in Tuner HAL 1.1, einem abwärtskompatiblen Versions-Upgrade von Tuner 1.0.

Verwenden Sie die folgende API, um die ausgeführte HAL-Version zu prüfen.

  • android.media.tv.tuner.TunerVersionChecker.getTunerVersion()

Die mindestens erforderliche HAL-Version finden Sie in der Dokumentation der neuen Android 12-APIs.

Pakete

Die Tuner SDK API bietet die vier unten aufgeführten Pakete.

  • android.media.tv.tuner
  • android.media.tv.tuner.frontend
  • android.media.tv.tuner.filter
  • android.media.tv.tuner.dvr

Ablaufdiagramm der Tuner SDK API-Pakete.

Abbildung 8. Tuner SDK API-Pakete

Android.media.tv.tuner

Das Tuner-Paket ist ein Einstiegspunkt für die Verwendung des Tuner-Frameworks. Die TIS-App verwendet das Paket, um Ressourceninstanzen zu initialisieren und abzurufen, indem die anfängliche Einstellung und der Callback angegeben werden.

  • tuner(): Initialisiert eine Tuner-Instanz durch Angabe der Parameter useCase und sessionId.
  • tune(): Ruft eine Frontend-Ressource und ‑Abstimmung ab, indem der Parameter FrontendSetting angegeben wird.
  • openFilter(): Ruft eine Filterinstanz ab, indem der Filtertyp angegeben wird.
  • openDvrRecorder(): Ruft eine Aufzeichnungsinstanz ab, indem die Puffergröße angegeben wird.
  • openDvrPlayback(): Ruft eine Wiedergabeinstanz ab, indem die Puffergröße angegeben wird.
  • openDescrambler(): Ruft eine Descrambler-Instanz ab.
  • openLnb(): Ruft eine interne LNB-Instanz ab.
  • openLnbByName(): Ruft eine externe LNB-Instanz ab.
  • openTimeFilter(): Ruft eine Zeitfilterinstanz ab.

Das Tuner-Paket bietet Funktionen, die nicht in den Filter-, DVR- und Frontend-Paketen enthalten sind. Die Funktionen sind unten aufgeführt.

  • cancelTuning
  • scan/cancelScanning
  • getAvSyncHwId
  • getAvSyncTime
  • connectCiCam1/disconnectCiCam
  • shareFrontendFromTuner
  • updateResourcePriority
  • setOnTuneEventListener
  • setResourceLostListener

Android.media.tv.tuner.frontend

Das Frontend-Paket enthält Sammlungen von Frontend-bezogenen Einstellungen, Informationen, Status, Ereignissen und Funktionen.

Klassen

FrontendSettings wird für verschiedene DTV-Standards aus den folgenden Klassen abgeleitet.

  • AnalogFrontendSettings
  • Atsc3FrontendSettings
  • AtscFrontendSettings
  • DvbcFrontendSettings
  • DvbsFrontendSettings
  • DvbtFrontendSettings
  • Isdbs3FrontendSettings
  • IsdbsFrontendSettings
  • IsdbtFrontendSettings

Ab Android 12 mit Tuner HAL 1.1 oder höher wird der folgende DTV-Standard unterstützt.

  • DtmbFrontendSettings

FrontendCapabilities wird für verschiedene DTV-Standards anhand der folgenden Klassen abgeleitet.

  • AnalogFrontendCapabilities
  • Atsc3FrontendCapabilities
  • AtscFrontendCapabilities
  • DvbcFrontendCapabilities
  • DvbsFrontendCapabilities
  • DvbtFrontendCapabilities
  • Isdbs3FrontendCapabilities
  • IsdbsFrontendCapabilities
  • IsdbtFrontendCapabilities

Ab Android 12 mit Tuner HAL 1.1 oder höher wird der folgende DTV-Standard unterstützt.

  • DtmbFrontendCapabilities

Mit FrontendInfo werden die Informationen des Front-Ends abgerufen. Mit FrontendStatus wird der aktuelle Status des Frontends abgerufen. OnTuneEventListener wartet auf Ereignisse im Frontend. Die TIS-App verwendet ScanCallback, um Scan-Nachrichten vom Frontend zu verarbeiten.

Kanalsuchlauf

Bei der Einrichtung eines Fernsehers scannt die App mögliche Frequenzen und erstellt eine Liste mit Kanälen, auf die Nutzer zugreifen können. TIS kann Tuner.tune, Tuner.scan(BLIND_SCAN) oder Tuner.scan(AUTO_SCAN) verwenden, um die Kanalsuche abzuschließen.

Wenn TIS genaue Informationen zur Signalübertragung hat, z. B. Frequenz, Standard (z. B. T/T2, S/S2) und zusätzliche erforderliche Informationen (z. B. PLD-ID), ist Tuner.tune die schnellere Option.

Wenn der Nutzer Tuner.tune aufruft, passieren folgende Aktionen:

  • TIS füllt FrontendSettings mit den erforderlichen Informationen über Tuner.tune aus.
  • Das HAL meldet LOCKED-Nachrichten, wenn das Signal gesperrt ist.
  • TIS verwendet Frontend.getStatus, um die erforderlichen Informationen zu erheben.
  • TIS wechselt zur nächsten verfügbaren Frequenz in der Frequenzliste.

TIS ruft Tuner.tune so lange auf, bis alle Frequenzen erschöpft sind.

Während der Optimierung kannst du stopTune() oder close() anrufen, um den Tuner.tune-Anruf zu pausieren oder zu beenden.

Tuner.scan(AUTO_SCAN)

Wenn TIS nicht genügend Informationen für die Verwendung von Tuner.tune hat, aber eine Frequenzliste und einen Standardtyp (z. B. DVB T/C/S), wird Tuner.scan(AUTO_SCAN) empfohlen.

Wenn der Nutzer Tuner.scan(AUTO_SCAN) aufruft, passieren folgende Aktionen:

  • Für TIS wird Tuner.scan(AUTO_SCAN) verwendet, wobei FrontendSettings mit der Häufigkeit gefüllt ist.

  • Das HAL meldet LOCKED-Nachrichten, wenn das Signal gesperrt ist. Das HAL kann auch andere Scanmeldungen ausgeben, um zusätzliche Informationen zum Signal bereitzustellen.

  • TIS verwendet Frontend.getStatus, um die erforderlichen Informationen zu erheben.

  • TIS ruft Tuner.scan für den HAL auf, um mit der nächsten Einstellung auf derselben Frequenz fortzufahren. Wenn die FrontendSettings-Struktur leer ist, verwendet die HAL die nächste verfügbare Einstellung. Andernfalls verwendet HAL FrontendSettings für einen einmaligen Scan und sendet END, um anzugeben, dass der Scanvorgang abgeschlossen ist.

  • TIS wiederholt die oben genannten Aktionen, bis alle Einstellungen für die Häufigkeit ausgeschöpft sind.

  • Die HAL sendet END, um anzugeben, dass der Scanvorgang abgeschlossen ist.

  • TIS wechselt zur nächsten verfügbaren Frequenz in der Frequenzliste.

TIS ruft Tuner.scan(AUTO_SCAN) so lange auf, bis alle Frequenzen erschöpft sind.

Während des Scannens können Sie stopScan() oder close() aufrufen, um den Scan zu pausieren oder zu beenden.

Tuner.scan(BLIND_SCAN)

Wenn TIS keine Frequenzliste hat und das Vendor-HAL nach der Frequenz des vom Nutzer angegebenen Frontends suchen kann, um die Frontend-Ressource zu erhalten, wird Tuner.scan(BLIND_SCAN) empfohlen.

  • TIS verwendet Tuner.scan(BLIND_SCAN). Eine Häufigkeit kann in FrontendSettings für die Starthäufigkeit angegeben werden, aber TIS ignoriert andere Einstellungen in FrontendSettings.
  • Das HAL meldet eine LOCKED-Nachricht, wenn das Signal gesperrt ist.
  • TIS verwendet Frontend.getStatus, um die erforderlichen Informationen zu erheben.
  • TIS ruft Tuner.scan noch einmal auf, um den Scan fortzusetzen. (FrontendSettings wird ignoriert.)
  • TIS wiederholt die oben genannten Aktionen, bis alle Einstellungen für die Häufigkeit ausgeschöpft sind. Die Häufigkeit wird vom HAL erhöht, ohne dass TIS etwas tun muss. Das HAL meldet PROGRESS.

TIS ruft Tuner.scan(AUTO_SCAN) so lange auf, bis alle Frequenzen erschöpft sind. Das HAL meldet END, um anzugeben, dass der Scanvorgang abgeschlossen ist.

Während des Scannens können Sie stopScan() oder close() anrufen, um den Scan zu pausieren oder zu beenden.

Flussdiagramm des TIS-Scan-Prozesses.

Abbildung 9. Flussdiagramm eines TIS-Scans

Android.media.tv.tuner.filter

Das Filterpaket ist eine Sammlung von Filtervorgängen zusammen mit Konfiguration, Einstellungen, Rückrufen und Ereignissen. Das Paket umfasst die folgenden Vorgänge. Eine vollständige Liste der Vorgänge finden Sie im Android-Quellcode.

  • configure()
  • start()
  • stop()
  • flush()
  • read()

Eine vollständige Liste finden Sie im Android-Quellcode.

FilterConfiguration wird aus den folgenden Klassen abgeleitet. Die Konfigurationen beziehen sich auf den Hauptfiltertyp und geben an, welches Protokoll der Filter zum Extrahieren von Daten verwendet.

  • AlpFilterConfiguration
  • IpFilterConfiguration
  • MmtpFilterConfiguration
  • TlvFilterConfiguration
  • TsFilterConfiguration

Die Einstellungen werden aus den folgenden Klassen abgeleitet. Die Einstellungen beziehen sich auf den Filter-Subtyp und geben an, welche Arten von Daten der Filter ausschließen kann.

  • SectionSettings
  • AvSettings
  • PesSettings
  • RecordSettings
  • DownloadSettings

FilterEvent wird aus den folgenden Klassen abgeleitet, um Ereignisse für verschiedene Arten von Daten zu melden.

  • SectionEvent
  • MediaEvent
  • PesEvent
  • TsRecordEvent
  • MmtpRecordEvent
  • TemiEvent
  • DownloadEvent
  • IpPayloadEvent

Ab Android 12 mit Tuner HAL 1.1 oder höher werden die folgenden Ereignisse unterstützt.

  • IpCidChangeEvent
  • RestartEvent
  • ScramblingStatusEvent
Ereignisse und Datenformat aus Filter
Filtertyp Flaggen Events Datenvorgang Datenformat
TS.SECTION
MMTP.SECTION
IP.SECTION
TLV.SECTION
ALP.SECTION
isRaw:
true
Erforderlich:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Empfohlen:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Führe
Filter.read(buffer, offset, adjustedSize) je nach Event und internem Zeitplan ein- oder mehrmals aus.

Daten werden aus dem MQ des HAL in den Clientpuffer kopiert.
Ein zusammengestelltes Sitzungspaket wird in FMQ durch ein anderes Sitzungspaket ersetzt.
isRaw:
false
Erforderlich:
DemuxFilterEvent::DemuxFilterSectionEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Optional:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++
Filter.read(buffer, offset, DemuxFilterSectionEven[i].size)


Daten werden aus dem MQ des HAL in den Clientpuffer kopiert.
TS.PES isRaw:
true
Erforderlich:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Empfohlen:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Führe
Filter.read(buffer, offset, adjustedSize) je nach Event und internem Zeitplan ein- oder mehrmals aus.

Daten werden aus der HAL-MQ in den Clientpuffer kopiert.
Ein zusammengesetztes PES-Paket wird in FMQ durch ein anderes PES-Paket gefüllt.
isRaw:
false
Erforderlich:
DemuxFilterEvent::DemuxFilterPesEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Optional:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++
Filter.read(buffer, offset, DemuxFilterPesEven[i].size)


Daten werden aus dem MQ des HAL in den Clientpuffer kopiert.
MMTP.PES isRaw:
true
Erforderlich:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Empfohlen:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Führe
Filter.read(buffer, offset, adjustedSize) je nach Event und internem Zeitplan ein- oder mehrmals aus.

Daten werden aus dem MQ des HAL in den Clientpuffer kopiert.
Ein zusammengestelltes MFU-Paket wird in FMQ durch ein anderes MFU-Paket gefüllt.
isRaw:
false
Erforderlich:
DemuxFilterEvent::DemuxFilterPesEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Optional:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++
Filter.read(buffer, offset, DemuxFilterPesEven[i].size)


Daten werden aus dem MQ des HAL in den Clientpuffer kopiert.
TS.TS
Erforderlich:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Empfohlen:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Führe
Filter.read(buffer, offset, adjustedSize) je nach Event und internem Zeitplan ein- oder mehrmals aus.

Daten werden aus dem MQ des HAL in den Clientpuffer kopiert.
ts mit ts-Header
wird in FMQ ausgefüllt.
TS.Audio
TS.Video
MMTP.Audio
MMTP.Video
isPassthrough:
true
Optional:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
Der Client kann MediaCodec starten, nachdem er DemuxFilterStatus::DATA_READY erhalten hat.
Der Client kann Filter.flush aufrufen, nachdem er DemuxFilterStatus::DATA_OVERFLOW erhalten hat.
isPassthrough:
false
Erforderlich:
DemuxFilterEvent::DemuxFilterMediaEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Optional:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
So verwenden Sie MediaCodec:
for i=0; i<n; i++
linearblock = MediaEvent[i].getLinearBlock();
codec.startQueueLinearBlock(linearblock)
linearblock.recycle()


So verwenden Sie Direct Audio von AudioTrack:
for i=0; i<n; i++
audioHandle = MediaEvent[i].getAudioHandle();
audiotrack.write(encapsulated(audiohandle))
ES- oder teilweise ES-Daten im ION-Speicher.
TS.PCR
IP.NTP
ALP.PTP
Obligatorisch:Nicht zutreffend
Optional:Nicht zutreffend
TS.RECORD Erforderlich:
DemuxFilterEvent::DemuxFilterTsRecordEvent[n]
RecordStatus::DATA_READY
RecordStatus::DATA_OVERFLOW
RecordStatus::LOW_WATER
RecordStatus::HIGH_WATER

Optional:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Für Indexdaten:
for i=0; i<n; i++
DemuxFilterTsRecordEvent[i];


Für aufgezeichnete Inhalte, gemäß RecordStatus::* und internem Zeitplan, führen Sie einen der folgenden Schritte aus:
  • Führen Sie DvrRecord.write(adustedSize) einmal oder mehrmals aus, um Daten zu speichern.
    Die Daten werden vom Message Queue des Hardware Abstraction Layer (HAL) in den Speicher übertragen.
  • Führen Sie DvrRecord.write(buffer, adustedSize) einmal oder mehrmals aus, um zu puffern.
    Die Daten werden aus dem MQ des HAL in den Clientpuffer kopiert.
Für Indexdaten:In der Ereignisnutzlast enthalten.

Bei aufgezeichneten Inhalten:Gemultiplexter TS-Stream, der in FMQ eingefügt wurde.
TS.TEMI Erforderlich
DemuxFilterEvent::DemuxFilterTemiEvent[n]

Optional
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++
DemuxFilterTemiEvent[i];
MMTP.MMTP Erforderlich:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Empfohlen:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Führe
Filter.read(buffer, offset, adjustedSize) je nach Event und internem Zeitplan ein- oder mehrmals aus.

Daten werden aus dem MQ des HAL in den Clientpuffer kopiert.
mmtp mit mmtp-Header
wird in FMQ ausgefüllt.
MMTP.RECORD Erforderlich:
DemuxFilterEvent::DemuxFilterMmtpRecordEvent[n]
RecordStatus::DATA_READY
RecordStatus::DATA_OVERFLOW
RecordStatus::LOW_WATER
RecordStatus::HIGH_WATER

Optional:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Für Indexdaten for i=0; i<n; i++
DemuxFilterMmtpRecordEvent[i];


Für aufgezeichnete Inhalte, gemäß RecordStatus::* und internem Zeitplan, führen Sie einen der folgenden Schritte aus:
  • Führen Sie DvrRecord.write(adjustedSize) ein- oder mehrmals aus, um Daten zu speichern.
    Die Daten werden vom Message Queue des Hardware-Abstraktionslayers (HAL) in den Speicher übertragen.
  • Führen Sie DvrRecord.write(buffer, adjustedSize)ein- oder mehrmals aus, um zu puffern.
    Die Daten werden aus dem MQ des HAL in den Clientpuffer kopiert.
Für Indexdaten:In der Ereignisnutzlast enthalten.

Für aufgezeichnete Inhalte:Gemischter aufgezeichneter Stream, der im FMQ ausgefüllt wird.

Wenn die Filterquelle für die Aufzeichnung TLV.TLV bis IP.IP mit Passthrough ist, hat der aufgezeichnete Stream einen TLV- und IP-Header.
MMTP.DOWNLOAD Erforderlich:
DemuxFilterEvent::DemuxFilterDownloadEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Optional:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++ Filter.read(buffer, offset, DemuxFilterDownloadEvent[i].size)

Daten werden aus dem HAL-MQ in den Clientpuffer kopiert.
Das Downloadpaket wird in FMQ durch ein anderes IP-Downloadpaket ersetzt.
IP.IP_PAYLOAD Erforderlich:
DemuxFilterEvent::DemuxFilterIpPayloadEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Optional:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++ Filter.read(buffer, offset, DemuxFilterIpPayloadEvent[i].size)

Daten werden aus dem HAL-MQ in den Clientpuffer kopiert.
Das IP-Nutzlastpaket wird in FMQ durch ein anderes IP-Nutzlastpaket gefüllt.
IP.IP
TLV.TLV
ALP.ALP
isPassthrough:
true
Optional:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
Der gefilterte Protokoll-Unterstream wird an den nächsten Filter in der Filterkette weitergeleitet.
isPassthrough:
false
Erforderlich:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Empfohlen:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Führe
Filter.read(buffer, offset, adjustedSize) je nach Event und internem Zeitplan ein- oder mehrmals aus.

Daten werden aus dem MQ des HAL in den Clientpuffer kopiert.
Gefilterter Protokoll-Unterstream mit ausgefülltem Protokollheader FMQ.
IP.PAYLOAD_THROUGH
TLV.PAYLOAD_THROUGH
ALP.PAYLOAD_THROUGH
Optional:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
Die herausgefilterte Protokollnutzlast wird an den nächsten Filter in der Filterkette weitergeleitet.
Beispiel für einen Ablauf zum Erstellen von PSI/SI mit einem Filter

Beispiel für einen Ablauf zum Erstellen von PSI/SI mit einem Filter.

Abbildung 10. Ablauf zum Erstellen von PSI/SI

  1. Öffnen Sie einen Filter.

    Filter filter = tuner.openFilter(
      Filter.TYPE_TS,
      Filter.SUBTYPE_SECTION,
      /* bufferSize */1000,
      executor,
      filterCallback
    );
    
  2. Konfigurieren und starten Sie den Filter.

    Settings settings = SectionSettingsWithTableInfo
        .builder(Filter.TYPE_TS)
        .setTableId(2)
        .setVersion(1)
        .setCrcEnabled(true)
        .setRaw(false)
        .setRepeat(false)
        .build();
      FilterConfiguration config = TsFilterConfiguration
        .builder()
        .setTpid(10)
        .setSettings(settings)
        .build();
      filter.configure(config);
      filter.start();
    
  3. Verarbeite SectionEvent.

    FilterCallback filterCallback = new FilterCallback() {
      @Override
      public void onFilterEvent(Filter filter, FilterEvent[] events) {
        for (FilterEvent event : events) {
          if (event instanceof SectionEvent) {
            SectionEvent sectionEvent = (SectionEvent) event;
            int tableId = sectionEvent.getTableId();
            int version = sectionEvent.getVersion();
            int dataLength = sectionEvent.getDataLength();
            int sectionNumber = sectionEvent.getSectionNumber();
            filter.read(buffer, 0, dataLength); }
          }
        }
    };
    
Beispiel für einen Ablauf zur Verwendung von „MediaEvent“ aus einem Filter

Beispiel für einen Ablauf zur Verwendung von „MediaEvent“ aus einem Filter.

Abbildung 11. Flow zum Verwenden von MediaEvent aus dem Filter

  1. Öffnen, konfigurieren und starten Sie die A/V-Filter.
  2. Verarbeite MediaEvent.
  3. MediaEvent erhalten
  4. Stellen Sie den linearen Block in die Warteschlange für codec.
  5. Geben Sie das A/V-Handle frei, wenn die Daten verwendet wurden.

Android.media.tv.tuner.dvr

DvrRecorder bietet diese Methoden für die Aufzeichnung.

  • configure
  • attachFilter
  • detachFilter
  • start
  • flush
  • stop
  • setFileDescriptor
  • write

DvrPlayback bietet diese Methoden für die Wiedergabe.

  • configure
  • start
  • flush
  • stop
  • setFileDescriptor
  • read

DvrSettings wird verwendet, um DvrRecorder und DvrPlayback zu konfigurieren. OnPlaybackStatusChangedListener und OnRecordStatusChangedListener werden verwendet, um den Status einer DVR-Instanz zu melden.

Beispiel für den Ablauf zum Starten einer Aufzeichnung

Beispiel für den Ablauf zum Starten einer Aufzeichnung.

Abbildung 12. Ablauf zum Starten einer Aufzeichnung

  1. Öffnen, konfigurieren und starten Sie DvrRecorder.

    DvrRecorder recorder = openDvrRecorder(/* bufferSize */ 1000, executor, listener);
    DvrSettings dvrSettings = DvrSettings
    .builder()
    .setDataFormat(DvrSettings.DATA_FORMAT_TS)
    .setLowThreshold(100)
    .setHighThreshold(900)
    .setPacketSize(188)
    .build();
    recorder.configure(dvrSettings);
    recorder.attachFilter(filter);
    recorder.setFileDescriptor(fd);
    recorder.start();
    
  2. RecordEvent empfangen und Indexinformationen abrufen

    FilterCallback filterCallback = new FilterCallback() {
      @Override
      public void onFilterEvent(Filter filter, FilterEvent[] events) {
        for (FilterEvent event : events) {
          if (event instanceof TsRecordEvent) {
            TsRecordEvent recordEvent = (TsRecordEvent) event;
            int tsMask = recordEvent.getTsIndexMask();
            int scMask = recordEvent.getScIndexMask();
            int packetId = recordEvent.getPacketId();
            long dataLength = recordEvent.getDataLength();
            // handle the masks etc. }
          }
        }
    };
    
  3. OnRecordStatusChangedListener initialisieren und die Datensatzdaten speichern.

      OnRecordStatusChangedListener listener = new OnRecordStatusChangedListener() {
        @Override
        public void onRecordStatusChanged(int status) {
          // a customized way to consume data efficiently by using status as a hint.
          if (status == Filter.STATUS_DATA_READY) {
            recorder.write(size);
          }
        }
      };
    

Tuner-HAL

Die Tuner-HAL folgt HIDL und definiert die Schnittstelle zwischen dem Framework und der Anbieterhardware. Anbieter verwenden die Schnittstelle, um die Tuner-HAL zu implementieren, und das Framework verwendet sie, um mit der Tuner-HAL-Implementierung zu kommunizieren.

Module

Tuner HAL 1.0

Module Grundlegende Bedienelemente Modulspezifische Steuerelemente HAL-Dateien
ITuner frontend(open, getIds, getInfo), openDemux, openDescrambler, openLnb, getDemuxCaps ITuner.hal
IFrontend setCallback, getStatus, close tune, stopTune, scan, stopScan, setLnb IFrontend.hal
IFrontendCallback.hal
IDemux close setFrontendDataSource, openFilter, openDvr, getAvSyncHwId, getAvSyncTime, connect / disconnectCiCam IDemux.hal
IDvr close, start, stop, configure attach/detachFilters, flush, getQueueDesc IDvr.hal
IDvrCallback.hal
IFilter close, start, stop, configure, getId flush, getQueueDesc, releaseAvHandle, setDataSource IFilter.hal
IFilterCallback.hal
ILnb close, setCallback setVoltage, setTone, setSatellitePosition, sendDiseqcMessage ILnb.hal
ILnbCallback.hal
IDescrambler close setDemuxSource, setKeyToken, addPid, removePid IDescrambler.hal

Tuner HAL 1.1 (abgeleitet von Tuner HAL 1.0)

Module Grundlegende Bedienelemente Modulspezifische Steuerelemente HAL-Dateien
ITuner getFrontendDtmbCapabilities @1.1::ITuner.hal
IFrontend tune_1_1, scan_1_1, getStatusExt1_1 link/unlinkCiCam @1.1::IFrontend.hal
@1.1::IFrontendCallback.hal
IFilter getStatusExt1_1 configureIpCid, configureAvStreamType, getAvSharedHandle, configureMonitorEvent @1.1::IFilter.hal
@1.1::IFilterCallback.hal

Ablaufdiagramm der Interaktionen zwischen den Modulen der Tuner-HAL.

Abbildung 13. Diagramm der Interaktionen zwischen den Tuner HAL-Modulen

Filterverknüpfung

Die Tuner HAL unterstützt die Verknüpfung von Filtern, sodass Filter für mehrere Ebenen mit anderen Filtern verknüpft werden können. Für die Filter gelten die folgenden Regeln.

  • Filter sind als Baum verknüpft. Ein geschlossener Pfad ist nicht zulässig.
  • Der Stammknoten ist „demux“.
  • Filter funktionieren unabhängig voneinander.
  • Alle Filter beginnen, Daten zu erfassen.
  • Die Filterverknüpfung wird beim letzten Filter geleert.

Der Codeblock unten und Abbildung 14 zeigen ein Beispiel für das Filtern mehrerer Ebenen.

demuxCaps = ITuner.getDemuxCap;
If (demuxCaps[IP][MMTP] == true) {
        ipFilter = ITuner.openFilter(<IP, ..>)
        mmtpFilter1 = ITuner.openFilter(<MMTP ..>)
        mmtpFilter2 = ITuner.openFilter(<MMTP ..>)
        mmtpFilter1.setDataSource(<ipFilter>)
        mmtpFilter2.setDataSource(<ipFilter>)
}

Diagramm mit einem Beispiel für die Verknüpfung von Filtern.

Abbildung 14. Flussdiagramm einer Filterverknüpfung für mehrere Ebenen

Tuner Resource Manager

Vor Tuner Resource Manager (TRM) war für das Umschalten zwischen zwei Apps dieselbe Tuner-Hardware erforderlich. Das TV Input Framework (TIF) hat einen Mechanismus verwendet, bei dem die App, die die Ressource zuerst erhält, sie auch behält. Für einige komplizierte Anwendungsfälle ist dieser Mechanismus jedoch möglicherweise nicht ideal.

TRM wird als Systemdienst ausgeführt, um die Hardware-Ressourcen für Tuner, TVInput und CAS für Apps zu verwalten. TRM verwendet einen Mechanismus für „Vordergrund-Gewinn“, bei dem die Priorität der App anhand des Vorder- oder Hintergrundstatus und des Anwendungsfalltyps berechnet wird. TRM gewährt oder entzieht die Ressource basierend auf der Priorität. TRM zentralisiert die Verwaltung von ATV-Ressourcen für Broadcast, OTT und DVR.

TRM-Schnittstelle

TRM stellt AIDL-Schnittstellen in ITunerResourceManager.aidl für das Tuner-Framework, MediaCas und TvInputHardwareManager bereit, um Ressourcen zu registrieren, anzufordern oder freizugeben.

Die Schnittstellen für die Kundenverwaltung sind unten aufgeführt.

  • registerClientProfile(in ResourceClientProfile profile, IResourcesReclaimListener listener, out int[] clientId)
  • unregisterClientProfile(in int clientId)

Die Schnittstellen zum Anfordern und Freigeben von Ressourcen sind unten aufgeführt.

  • requestFrontend(TunerFrontendRequest request, int[] frontendHandle) / releaseFrontend
  • requestDemux(TunerDemuxRequest request, int[] demuxHandle) / releaseDemux
  • requestDescrambler(TunerDescramblerRequest request, int[] descramblerHandle) / releaseDescrambler
  • requestCasSession(CasSessionRequest request, int[] casSessionHandle) / releaseCasSession
  • requestLnb(TunerLnbRequest request, int[] lnbHandle)/releaseLnb

Client- und Anfrageklassen sind unten aufgeführt.

  • ResourceClientProfile
  • ResourcesReclaimListener
  • TunerFrontendRequest
  • TunerDemuxRequest
  • TunerDescramblerRequest
  • CasSessionRequest
  • TunerLnbRequest

Clientpriorität

TRM berechnet die Priorität des Clients anhand von Parametern aus dem Profil des Clients und dem Prioritätswert aus der Konfigurationsdatei. Die Priorität kann auch durch einen beliebigen Prioritätswert vom Client aktualisiert werden.

Parameter im Profil des Kunden

TRM ruft die Prozess-ID aus mTvInputSessionId ab, um zu entscheiden, ob eine App eine Vordergrund- oder Hintergrund-App ist. Zum Erstellen von mTvInputSessionId initialisiert TvInputService.onCreateSession oder TvInputService.onCreateRecordingSession eine TIS-Sitzung.

mUseCase gibt den Anwendungsfall der Sitzung an. Die vordefinierten Anwendungsfälle sind unten aufgeführt.

TvInputService.PriorityHintUseCaseType  {
  PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK
  PRIORITY_HINT_USE_CASE_TYPE_LIVE
  PRIORITY_HINT_USE_CASE_TYPE_RECORD,
  PRIORITY_HINT_USE_CASE_TYPE_SCAN,
  PRIORITY_HINT_USE_CASE_TYPE_BACKGROUND
}

Konfigurationsdatei

Standardkonfigurationsdatei

Die Standardkonfigurationsdatei unten enthält Prioritätswerte für vordefinierte Anwendungsfälle. Nutzer können die Werte mit einer benutzerdefinierten Konfigurationsdatei ändern.

Anwendungsfall Vordergrund Hintergrund
LIVE 490 400
PLAYBACK 480 300
RECORD 600 500
SCAN 450 200
BACKGROUND 180 100
Benutzerdefinierte Konfigurationsdatei

Anbieter können die Konfigurationsdatei /vendor/etc/tunerResourceManagerUseCaseConfig.xml anpassen. Mit dieser Datei können Sie die Anwendungsfalltypen und die Prioritätswerte für Anwendungsfälle hinzufügen, entfernen oder aktualisieren. Die angepasste Datei kann platform/hardware/interfaces/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml als Vorlage verwenden.

Ein Beispiel für einen neuen Anwendungsfall für Anbieter ist VENDOR_USE_CASE__[A-Z0-9]+, [0 - 1000]. Das Format sollte platform/hardware/interfaces/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfig.xsd entsprechen.

Beliebiger Prioritätswert und „nice“-Wert

TRM stellt updateClientPriority für den Client bereit, damit dieser den beliebigen Prioritätswert und den Nice-Wert aktualisieren kann. Der beliebige Prioritätswert überschreibt den Prioritätswert, der aus dem Anwendungsfalltyp und der Sitzungs-ID berechnet wird.

Der „nice“-Wert gibt an, wie kulant sich der Client verhält, wenn er mit einem anderen Client in Konflikt gerät. Der „nice“-Wert verringert den Prioritätswert des Clients, bevor er mit dem des Challenging-Clients verglichen wird.

Reaktivierungsmechanismus

Das folgende Diagramm zeigt, wie Ressourcen zurückgefordert und zugewiesen werden, wenn ein Ressourcenkonflikt auftritt.

Diagramm des Prozesses für die Rückforderung von Speicherplatz.

Abbildung 15. Diagramm des Rückforderungsmechanismus bei einem Konflikt zwischen Tuner-Ressourcen