Tuner-Framework

Unter Android 11 oder höher kannst du das Android Tuner-Framework verwenden, um A/V-Inhalte bereitzustellen. Das Framework nutzt die Hardwarepipeline der Anbieter 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 vertrauenswürdige Ausführungsumgebung (Trusted Execution Environment, TEE) und einen sicheren Medienpfad (Secure Media Path, SMP) geschützt sind. So kann es in einer stark eingeschränkten Umgebung für den Schutz von Inhalten verwendet werden.

Die standardisierte Schnittstelle zwischen Tuner und Android CAS sorgt für eine schnellere Integration zwischen Tuner- und CAS-Anbietern. Die Benutzeroberfläche des Tuner arbeitet mit MediaCodec und AudioTrack zusammen, um eine universelle Lösung für Android TV zu erstellen. Die Tuner-Oberfläche unterstützt sowohl digitales als auch analoges Fernsehen auf Grundlage der wichtigsten Übertragungsstandards.

Komponenten

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

  • Tuner HAL: Eine Schnittstelle zwischen dem Framework und den Anbietern.
  • Tuner SDK API:Eine Schnittstelle zwischen dem Framework und den Apps
  • Tuner Resource Manager (TRM): HW-Ressourcen für Koordinaten-Tuner

Für Android 11 wurden die folgenden Komponenten optimiert.

  • CAS V2
  • TvInputService oder TV-Eingabedienst (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 Front-End unterstützt die folgenden DTV-Standards.

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

Das Front-End in Android 12 mit Tuner HAL 1.1 oder höher unterstützt den unten stehenden DTV-Standard.

  • DTMB

Demux unterstützt die unten aufgeführten Stream-Protokolle.

  • Transport stream (TS)
  • MPEG Media Transport Protocol (MMTP)
  • Internet Protocol (IP)
  • Type Length Value (TLV)
  • ATSC-Link-Ebenen-Protokoll (ALP)

Descrambler unterstützt die unten aufgeführten Schutzmaßnahmen für Inhalte.

  • Sicherer Medienpfad
  • Medienpfad löschen
  • Lokalen Eintrag sichern
  • Lokale Wiedergabe schützen

Tuner-APIs unterstützen die folgenden Anwendungsfälle.

  • Scannen
  • Live
  • Wiedergabe
  • Aufnehmen

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

  • ES-Nutzlast mit leeren Arbeitsspeicher-Puffer
  • ES-Nutzlast mit sicherem Speicher-Handle
  • Passthrough

Design allgemein

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

  • Beschreibt, was das Framework vom Anbieter erwartet und wie er dies tun könnte
  • 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 zur Einbindung des Tuner-HAL in andere Framework-Komponenten wie MediaCodec und AudioTrack.

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

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

Eine TRM-Klasse wird erstellt.

  • Verwaltet eingeschränkte Tuner-Ressourcen wie Frontend, LNB, CAS-Sitzungen und ein TV-Eingabegerät über den TV-Eingabe-HAL.
  • Es werden Regeln angewendet, um nicht ausreichende Ressourcen aus Apps zurückzugewinnen. Die Standardregel ist der Sieg im Vordergrund.

Media CAS und die CAS HAL wurden um die folgenden Funktionen erweitert.

  • Öffnet CAS-Sitzungen für verschiedene Verwendungen und Algorithmen.
  • Unterstützt dynamische CAS-Systeme wie das Entfernen und Einfügen von CICAM.
  • Lässt sich in den Tuner HAL einbinden, indem Schlüsseltokens bereitgestellt werden.

MediaCodec und AudioTrack wurden um die folgenden Funktionen erweitert.

  • Nimmt sicheren A/V-Speicher als Inhaltseingabe an.
  • Konfiguriert für die A/V-Synchronisation der Hardware bei getunnelter Wiedergabe
  • Die 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 zeigen Aufrufsequenzen für die Wiedergabe von Liveübertragungen.

Einrichten

Diagramm für die Wiedergabe von Liveübertragungen einrichten

Abbildung 3: Sequenz für die Wiedergabe von Liveübertragungen einrichten

Umgang mit A/V

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

Abbildung 4: Umgang mit dem A/V bei der Wiedergabe von Live-Übertragungen

Umgang mit verschlüsselten Inhalten

Diagramm zum Umgang mit verschlüsselten Inhalten bei der Wiedergabe von Liveübertragungen

Abbildung 5. Umgang mit verschlüsselten Inhalten für die Wiedergabe von Liveübertragungen

A/V-Daten werden verarbeitet

A/V-Daten für ein Diagramm zur Wiedergabe von Liveübertragungen verarbeiten

Abbildung 6: Verarbeitung des Audio-/Video-Contents für die Wiedergabe von Live-Übertragungen

Tuner SDK API

Die Tuner SDK API verarbeitet die Interaktionen mit der Tuner-JNI, dem Tuner-HAL und dem TunerResourceManager. Die TIS-App verwendet die Tuner SDK API, um auf Tuner-Ressourcen und Unterkomponenten wie den Filter und den Dekoder 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 Versionsupgrade 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 Mindestversion der HAL finden Sie in der Dokumentation der neuen Android 12 APIs.

Pakete

Die Tuner SDK API bietet die vier folgenden Pakete.

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

Flussdiagramm 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 zu erwerben. Dazu werden die Anfangseinstellung und der Callback angegeben.

  • tuner(): Initialisiert eine Tunerinstanz durch Angabe der Parameter useCase und sessionId.
  • tune(): Bezieht eine Frontend-Ressource und stimmt durch Angabe des Parameters FrontendSetting ab.
  • openFilter(): Hiermit wird eine Filterinstanz durch Angabe des Filtertyps abgerufen.
  • openDvrRecorder(): Erwirbt eine Aufnahmeinstanz, indem die Puffergröße angegeben wird.
  • openDvrPlayback(): Erhält eine Wiedergabeinstanz, indem die Puffergröße angegeben wird.
  • openDescrambler(): Erhält eine Descrambler-Instanz.
  • openLnb(): Bezieht eine interne LNB-Instanz.
  • openLnbByName(): Bezieht eine externe LNB-Instanz.
  • openTimeFilter(): Ruft eine Zeitfilterinstanz ab.

Das Tuner-Paket bietet Funktionen, die nicht durch die Filter-, DVR- und Frontend-Pakete abgedeckt sind. Die Funktionen sind unten aufgeführt.

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

Android.media.tv.tuner.frontend

Das Front-End-Paket enthält Sammlungen von Front-End-bezogenen Einstellungen, Informationen, Statuswerten, Ereignissen und Funktionen.

Klassen

FrontendSettings wird für verschiedene DTV-Standards von 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 durch die 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

FrontendInfo ruft die Informationen des Front-Ends ab. FrontendStatus ruft den aktuellen Status des Front-Ends ab. OnTuneEventListener überwacht die Ereignisse im Frontend. Die TIS-App verwendet ScanCallback, um Scannachrichten vom Frontend zu verarbeiten.

Kanalsuchlauf

Um einen Fernseher einzurichten, scannt die App mögliche Frequenzen und erstellt ein Kanalangebot, auf das 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 korrekte Übermittlungsinformationen für das Signal hat, z. B. Frequenz, Standard (z. B. T/T2, S/S2) und weitere erforderliche Informationen (z. B. PLD-ID), wird Tuner.tune als schnellere Option empfohlen.

Wenn der Nutzer Tuner.tune anruft, geschieht Folgendes:

  • TIS füllt FrontendSettings mithilfe von Tuner.tune mit den erforderlichen Informationen.
  • Die 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 noch einmal auf, bis alle Frequenzen ausgeschöpft sind.

Während der Abstimmung kannst du stopTune() oder close() aufrufen, um den Tuner.tune-Aufruf 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) hat, wird Tuner.scan(AUTO_SCAN) empfohlen.

Wenn der Nutzer Tuner.scan(AUTO_SCAN) aufruft, werden die folgenden Aktionen ausgeführt:

  • Bei TIS wird Tuner.scan(AUTO_SCAN) mit der Häufigkeit FrontendSettings verwendet.

  • Die HAL-Berichte scannen LOCKED Nachrichten, wenn das Signal gesperrt ist. Der HAL kann auch andere Scannachrichten senden, um zusätzliche Informationen zum Signal bereitzustellen.

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

  • TIS ruft Tuner.scan für den HAL auf, um mit der nächsten Einstellung mit derselben Häufigkeit 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 erschöpft sind.

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

  • Mit TIS wird die nächste verfügbare Frequenz in der entsprechenden Häufigkeitsliste ausgewählt.

TIS ruft Tuner.scan(AUTO_SCAN) noch einmal auf, bis alle Frequenzen ausgeschöpft sind.

Während des Scannens können Sie stopScan() oder close() drücken, um den Vorgang zu pausieren oder zu beenden.

Tuner.scan(BLIND_SCAN)

Wenn TIS keine Häufigkeitsliste hat und der Anbieter-HAL nach der Häufigkeit des vom Nutzer angegebenen Front-Ends suchen kann, um die Front-End-Ressource abzurufen, wird Tuner.scan(BLIND_SCAN) empfohlen.

  • TIS verwendet Tuner.scan(BLIND_SCAN). In FrontendSettings kann eine Häufigkeit für den Start angegeben werden. Andere Einstellungen in FrontendSettings werden von TIS jedoch ignoriert.
  • Die HAL meldet eine Scan-LOCKED-Nachricht, wenn das Signal gesperrt ist.
  • TIS verwendet Frontend.getStatus, um die erforderlichen Informationen zu erfassen.
  • TIS ruft Tuner.scan noch einmal auf, um mit dem Scannen fortzufahren. FrontendSettings wird ignoriert.
  • TIS wiederholt die oben genannten Aktionen, bis alle Einstellungen für die Frequenz ausgeschöpft sind. Die HAL erhöht die Häufigkeit, ohne dass TIS etwas tun muss. Der HAL meldet PROGRESS.

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

Während des Scans können Sie stopScan() oder close() drücken, um den Scan zu pausieren oder zu beenden.

Flussdiagramm des TIS-Scanvorgangs.

Abbildung 9: Flussdiagramm eines TIS-Scans

Android.media.tv.tuner.filter

Das Filterpaket ist eine Sammlung von Filtervorgängen sowie Konfigurationen, Einstellungen, Rückrufen und Ereignissen. Das Paket enthält die folgenden Vorgänge. Die 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 gelten für 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 gelten für den Filteruntertyp und geben an, welche Daten vom Filter ausgeschlossen werden können.

  • SectionSettings
  • AvSettings
  • PesSettings
  • RecordSettings
  • DownloadSettings

FilterEvent wird aus den unten aufgeführten Klassen abgeleitet, um Ereignisse für verschiedene Datentypen zu erfassen.

  • 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 dem Filter
Filtertyp Flaggen Ereignisse 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ühren Sie den
Filter.read(buffer, offset, adjustedSize) gemäß der Veranstaltung und dem internen Zeitplan einmal oder mehrmals aus.

Die Daten werden aus dem MQ von HAL in den Client-Puffer kopiert.
Ein zusammengesetztes Sitzungspaket wird in der FMQ durch ein anderes Sitzungspaket gefüllt.
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)


Die Daten werden aus dem MQ von HAL in den Client-Puffer kopiert.
TS.PES isRaw:
true
Erforderlich:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Empfohlen:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Führen Sie
Filter.read(buffer, offset, adjustedSize) gemäß dem Ereignis und dem internen Zeitplan ein- oder mehrmals aus.

Daten werden aus dem MQ des HAL in den Clientzwischenspeicher kopiert.
Ein zusammengesetztes PES-Paket wird in FMQ von einem anderen PES-Paket ausgefü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 von HAL in den Clientzwischenspeicher kopiert.
MMTP.PES isRaw:
true
Erforderlich:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Empfohlen:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Führen Sie
Filter.read(buffer, offset, adjustedSize) gemäß dem Ereignis und dem internen Zeitplan ein- oder mehrmals aus.

Daten werden aus dem MQ des HAL in den Clientzwischenspeicher kopiert.
Ein zusammengesetztes MFU-Paket wird in FMQ durch ein anderes MFU-Paket ausgefü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 Client-Zwischenspeicher kopiert.
TS.TS
Erforderlich:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Empfohlen:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Führen Sie den
Filter.read(buffer, offset, adjustedSize) gemäß der Veranstaltung und dem internen Zeitplan einmal oder mehrmals aus.

Daten werden aus dem MQ der HAL in den Client-Puffer kopiert.
Ausgefilterte 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 empfangen hat.
Der Client kann Filter.flush aufrufen, nachdem DemuxFilterStatus::DATA_OVERFLOW empfangen wurde.
isPassthrough:
false
Obligatorisch:
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
Erforderlich: –
Optional: –
TS.RECORD Obligatorisch:
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ühre bei aufgezeichneten Inhalten gemäß RecordStatus::* und dem internen Zeitplan einen der folgenden Schritte aus:
  • Führen Sie DvrRecord.write(adustedSize) einmal oder mehrmals auf den Speicher aus.
    Die Daten werden aus dem MQ des HAL in den Speicher übertragen.
  • Führen Sie DvrRecord.write(buffer, adustedSize) zur Zwischenspeicherung mindestens einmal aus.
    Die Daten werden aus dem MQ des HAL in den Clientzwischenspeicher kopiert.
Für Indexdaten: Werden in Ereignisnutzlast übertragen.

Für aufgenommene Inhalte:Muxed TS-Stream in FMQ gefüllt.
TS.TEMI Obligatorisch:
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ühren Sie
Filter.read(buffer, offset, adjustedSize) gemäß dem Ereignis und dem internen Zeitplan ein- oder mehrmals aus.

Daten werden aus dem MQ des HAL in den Clientzwischenspeicher kopiert.
Der herausgefilterte mmtp mit dem 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
Indexdaten: for i=0; i<n; i++
DemuxFilterMmtpRecordEvent[i];


Aufgezeichnete Inhalte: Führe gemäß RecordStatus::* und dem internen Zeitplan eine der folgenden Aktionen aus:
  • Führen Sie DvrRecord.write(adjustedSize) mindestens einmal auf den Speicher aus.
    Die Daten werden aus dem MQ der HAL in den Speicher übertragen.
  • Führen Sie DvrRecord.write(buffer, adjustedSize) zur Zwischenspeicherung einmal oder mehrmals aus.
    Die Daten werden aus dem MQ des HAL in den Clientzwischenspeicher kopiert.
Für Indexdaten: Werden in Ereignisnutzlast übertragen.

Für aufgezeichnete Inhalte: Muxed-Aufnahmestream wurde in FMQ gefüllt.

Wenn die Filterquelle für die Aufzeichnung TLV.TLV bis IP.IP mit Passthrough ist, hat der aufgezeichnete Stream einen TLV- und einen IP-Header.
MMTP.DOWNLOAD Obligatorisch:
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)

Die Daten werden aus dem MQ von HAL in den Client-Puffer kopiert.
Das Downloadpaket wird in FMQ von einem anderen IP-Downloadpaket gefüllt.
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)

Die Daten werden aus dem MQ von HAL in den Client-Puffer kopiert.
Das IP-Nutzlastpaket wird in der FMQ durch ein anderes IP-Nutzlastpaket gefüllt.
IP.IP
TLV.TLV
ALP.ALP
isPassthrough:
true
Optional:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
Der herausgefilterte 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ühren Sie
Filter.read(buffer, offset, adjustedSize) gemäß dem Ereignis und dem internen Zeitplan ein- oder mehrmals aus.

Daten werden aus dem MQ des HAL in den Clientzwischenspeicher kopiert.
Der herausgefilterte Protokoll-Substream mit Protokoll-Header wird in FMQ ausgefüllt.
IP.PAYLOAD_THROUGH
TLV.PAYLOAD_THROUGH
ALP.PAYLOAD_THROUGH
Optional:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
Durch die herausgefilterten Protokollnutzlasten wird der nächste Filter in der Filterkette gespeist.
Beispiel für die Verwendung eines Filters zum Erstellen von PSI/SI

Beispiel für die Verwendung eines Filters zum Erstellen von PSI/SI

Abbildung 10. Vorgang 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. SectionEvent verarbeiten

    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); }
          }
        }
    };
    
Beispielablauf für die Verwendung von MediaEvent aus einem Filter

Beispielablauf für die Verwendung von MediaEvent aus einem Filter

Abbildung 11 Ablauf zum Verwenden von „MediaEvent“ aus dem Filter

  1. Öffnen, konfigurieren und starten Sie die Audio-/Videofilter.
  2. MediaEvent verarbeiten
  3. MediaEvent erhalten.
  4. Stellen Sie den linearen Block in die Warteschlange für codec.
  5. Lassen Sie den A/V-Handle los, wenn die Daten verbraucht sind.

Android.media.tv.tuner.dvr

DvrRecorder bietet folgende Aufnahmemethoden.

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

DvrPlayback bietet folgende Wiedergabemethoden.

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

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

Beispiel für den Ablauf zum Starten eines Datensatzes

Beispiel für einen Ablauf zum Starten einer Aufnahme.

Abbildung 12. Ablauf zum Starten eines Eintrags

  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. Sie erhalten RecordEvent und rufen die Indexinformationen ab.

    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. Initialisieren Sie OnRecordStatusChangedListener und speichern Sie die Datensatzdaten.

      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 Hardware des Anbieters. Anbieter verwenden die Schnittstelle, um den Tuner-HAL zu implementieren, und das Framework verwendet sie für die Kommunikation mit der Tuner-HAL-Implementierung.

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

Flussdiagramm der Interaktionen zwischen den Modulen der Tuner HAL.

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

Filterverknüpfung

Der Tuner-HAL unterstützt eine Filterverknüpfung, mit der 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 Root-Knoten ist demux.
  • Filter funktionieren unabhängig voneinander.
  • Für alle Filter werden Daten abgerufen.
  • Durch die Filterverknüpfung wird der letzte Filter ausgeblendet.

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 zum Beispiel für eine Filterverknüpfung.

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

Tuner Resource Manager

Vor dem Tuner Resource Manager (TRM) war für den Wechsel zwischen zwei Anwendungen dieselbe Tuner-Hardware erforderlich. Das TV Input Framework (TIF) verwendete einen Mechanismus, 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 Tuner-, TVInput- und CAS-Hardwareressourcen für Apps zu verwalten. Bei der TRM-Funktion wird ein Mechanismus verwendet, der die Priorität der App basierend auf dem Status im Vordergrund oder Hintergrund und dem Anwendungsfall berechnet. TRM gewährt oder entzieht die Ressource basierend auf der Priorität. TRM zentralisiert die ATV-Ressourcenverwaltung für Broadcasting, OTT und DVR.

TRM-Schnittstelle

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

Die Oberflächen 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

Kundenprioritä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 von mTvInputSessionId ab, um zu entscheiden, ob eine App eine Anwendung im Vordergrund oder im Hintergrund ist. Zum Erstellen von mTvInputSessionId initialisieren 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 folgende Standardkonfigurationsdatei enthält Prioritätswerte für vordefinierte Anwendungsfälle. Nutzer können die Werte mithilfe 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 anpassen. Diese Datei wird verwendet, um die Anwendungsfalltypen und die Prioritätswerte für Anwendungsfälle hinzuzufügen, zu entfernen oder zu aktualisieren. Die benutzerdefinierte Datei kann platform/hardware/interfaces/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml als Vorlage verwenden.

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

Willkürlicher Prioritätswert und Nice-Wert

TRM stellt updateClientPriority für den Client bereit, um den beliebigen Prioritätswert und den Nice-Wert zu aktualisieren. Der beliebige Prioritätswert überschreibt den aus dem Anwendungsfalltyp und der Sitzungs-ID berechneten Prioritätswert.

Der Wert „nice“ gibt an, wie tolerant das Verhalten des Clients ist, wenn er mit einem anderen Client in Konflikt steht. Der Wert „nett“ verringert den Prioritätswert des Kunden, bevor sein Prioritätswert mit dem des schwierigen Kunden verglichen wird.

Reaktivierungsmechanismus

Das folgende Diagramm zeigt, wie Ressourcen bei einem Ressourcenkonflikt zurückgefordert und neu zugewiesen werden.

Diagramm des Ablaufs des Rückforderungsmechanismus.

Abbildung 15. Diagramm des Rückforderungsmechanismus bei einem Konflikt zwischen Tunerressourcen