Platforma tunera

W przypadku Androida 11 lub nowszego możesz używać platformy Android Tuner do przesyłania treści audiowizualnych. Framework korzysta z przesyłu sprzętowego od dostawców, dzięki czemu jest odpowiedni zarówno do nisko-, jak i wysoko zaawansowanych układów SoC. Framework zapewnia bezpieczny sposób dostarczania treści audiowizualnych chronionych przez zaufane środowisko wykonawcze (TEE) i bezpieczną ścieżkę multimediów (SMP), co pozwala na jego używanie w bardzo ograniczonym środowisku chroniącym treści.

Standardowy interfejs między Tunerem a Android CAS umożliwia szybszą integrację między dostawcami tunerów a dostawcami CAS. Interfejs Tunera współpracuje z MediaCodecAudioTrack, aby tworzyć jedno uniwersalne rozwiązanie na Androida TV. Interfejs tunera obsługuje telewizję cyfrową i analogową zgodnie z głównymi standardami nadawania.

Komponenty

W Androidzie 11 3 komponenty są specjalnie zaprojektowane pod kątem platformy TV.

  • Tuner HAL: interfejs między frameworkiem a dostawcami.
  • Tuner SDK API: interfejs między platformą a aplikacjami.
  • Menedżer zasobów tunera (TRM): koordynuje zasoby sprzętowe tunera.

W Androidzie 11 ulepszono te komponenty:

  • CAS V2
  • TvInputService lub usługa wprowadzania danych w telewizorze (TIS)
  • TvInputManagerService lub usługa TIMS (TV Input Manager Service)
  • MediaCodec lub kodek multimediów
  • AudioTrack lub ścieżka audio
  • MediaResourceManager lub menedżer zasobów medialnych (MRM)

Schemat blokowy komponentów ramki Tunera

Rysunek 1. Interakcje między komponentami Androida TV

Funkcje

Frontend obsługuje te standardy DTV:

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

Frontend w Androidzie 12 z Tuner HAL 1.1 lub nowszym obsługuje standard DTV.

  • DTMB

Demux obsługuje te protokoły strumieniowe:

  • strumień transportu (TS);
  • MPEG Media Transfer Protocol (MMTP)
  • Protokół internetowy (IP)
  • Typ długości wartości (TLV)
  • Protokół warstwy łącza ATSC (ALP)

Descrambler obsługuje te zabezpieczenia treści.

  • Bezpieczna ścieżka multimediów
  • Wyczyść ścieżkę multimediów
  • Zabezpieczanie rekordu lokalnego
  • Bezpieczne odtwarzanie lokalne

Interfejsy API tunera obsługują te zastosowania.

  • Skanuj
  • Na żywo
  • Odtwarzanie
  • Nagrywaj

Tuner, MediaCodecAudioTrack obsługują te tryby przepływu danych:

  • Dane ładunku ES z buforem pamięci o czystej pamięci
  • Payload ES z bezpiecznym uchwytem pamięci
  • Widok otoczenia

Ogólny projekt

Interfejs HAL tunera jest definiowany między platformą Androida a sprzętem dostawcy.

  • Opisuje, czego oczekuje się od dostawcy w ramach tej ramy, i jak może on to osiągnąć.
  • Eksportuje funkcje interfejsu frontendu, demuxera i dekoderu do frameworku za pomocą interfejsów IFrontend, IDemux, IDescrambler, IFilter, IDvr i ILnb.
  • Zawiera funkcje umożliwiające zintegrowanie interfejsu HAL Tunera z innymi komponentami frameworku, takimi jak MediaCodecAudioTrack.

Tworzona jest klasa Java i klasa natywna.

  • Interfejs Tuner Java API umożliwia aplikacjom dostęp do interfejsu HAL Tunera za pomocą publicznych interfejsów API.
  • Klasa natywnych umożliwia kontrolę uprawnień i obsługę dużych ilości danych dotyczących nagrywania lub odtwarzania za pomocą interfejsu HAL tunera.
  • Natywczy moduł tunera stanowi łącznik między klasą Java Tunera a interfejsem HAL Tunera.

Tworzona jest klasa TRM.

  • Zarządza ograniczonymi zasobami tunera, takimi jak front-end, LNB, sesje CAS i urządzenie wejściowe TV z poziomu interfejsu HAL wejścia TV.
  • Stosuje reguły, aby odzyskać zasoby z aplikacji, których jest za mało. Regułą domyślną jest wygrana pierwszego planu.

Media CAS i CAS HAL zostały ulepszone o te funkcje.

  • Otwiera sesje CAS na potrzeby różnych zastosowań i algorytmów.
  • Obsługuje dynamiczne systemy CAS, takie jak usuwanie i wstawianie CICAM.
  • Integruje się z Tuner HAL, udostępniając tokeny kluczy.

MediaCodec i AudioTrack zostały wzbogacone o te funkcje:

  • Odczytuje zabezpieczoną pamięć audiowizualną jako dane wejściowe.
  • Konfiguracja sprzętowego synchronizatora audio-wideo w przypadku odtwarzania tunelowanego.
  • Skonfigurowano obsługę ES_payload i trybu przepuszczania.

Ogólny projekt interfejsu Tuner HAL.

Rysunek 2. Schemat komponentów w Tuner HAL

Ogólny przepływ pracy

Diagramy poniżej przedstawiają sekwencje wywołań podczas odtwarzania transmisji na żywo.

Konfiguracja

Sekwencja konfiguracji odtwarzania transmisji na żywo

Rysunek 3. Sekwencja konfiguracji odtwarzania transmisji na żywo

Obsługa A/V

Schemat obsługi dźwięku i obrazu w przypadku odtwarzania transmisji na żywo

Rysunek 4. Obsługa dźwięku i obrazu podczas odtwarzania transmisji na żywo

Postępowanie z treściami zaszyfrowanymi

Schemat obsługi szyfrowanych treści w przypadku odtwarzania transmisji na żywo

Rysunek 5. Postępowanie z zakodowanymi treściami podczas odtwarzania transmisji na żywo

Przetwarzanie danych audio-wizualnych

Przetwarzanie danych audiowizualnych na potrzeby diagramu odtwarzania transmisji na żywo.

Rysunek 6. Przetwarzanie obrazu i dźwięku w celu odtworzenia transmisji na żywo

Interfejs API Tuner SDK

Interfejs API pakietu Tuner SDK obsługuje interakcje z interfejsem JNI Tunera, interfejsem HAL Tunera i interfejsem TunerResourceManager. Aplikacja TIS korzysta z interfejsu API Tuner SDK, aby uzyskać dostęp do zasobów tunera i jego podkomponentów, takich jak filtr i dekoder. Frontend i demux to komponenty wewnętrzne.

Schemat przepływu interfejsu API pakietu Tuner SDK

Rysunek 7. Interakcje z interfejsem Tuner SDK API

Wersje

Od Androida 12 interfejs API pakietu Tuner SDK obsługuje nową funkcję w interfejsie Tuner HAL 1.1, który jest kompatybilny wstecz z wersją Tuner 1.0.

Aby sprawdzić wersję interfejsu HAL, użyj tego interfejsu API.

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

Minimalną wymaganą wersję HAL znajdziesz w dokumentacji nowych interfejsów API Androida 12.

Pakiety

Interfejs API Tuner SDK udostępnia 4 pakiety:

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

Schemat przepływu pakietów interfejsu API Tuner SDK

Rysunek 8. Pakiety interfejsu API pakietu Tuner SDK

Android.media.tv.tuner

Pakiet Tuner to punkt wejścia do korzystania z ramy Tuner. Aplikacja TIS używa pakietu do inicjowania i uzyskiwania instancji zasobów przez określenie początkowego ustawienia i wywołania zwrotnego.

  • tuner(): inicjalizuje wystąpienie Tunera przez podanie parametrów useCasesessionId.
  • tune(): pobiera zasób interfejsu i dostosowuje go przez podanie parametru FrontendSetting.
  • openFilter(): pobiera instancję filtra przez określenie typu filtra.
  • openDvrRecorder(): umożliwia uzyskanie instancji nagrywania przez określenie rozmiaru bufora.
  • openDvrPlayback(): pobiera instancję odtwarzania, podając rozmiar bufora.
  • openDescrambler(): pobiera instancję deszyfratora.
  • openLnb(): pobiera wewnętrzną instancję LNB.
  • openLnbByName(): uzyskuje zewnętrzne wystąpienie LNB.
  • openTimeFilter(): pobiera instancję filtra czasowego.

Pakiet Tuner udostępnia funkcje, które nie są dostępne w pakietach filtrów, DVR i interfejsu. Funkcje te znajdziesz poniżej.

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

Android.media.tv.tuner.frontend

Pakiet interfejsu zawiera kolekcje ustawień, informacji, stanów, zdarzeń i możliwości związanych z interfejsem.

Zajęcia

FrontendSettings jest obliczana dla różnych standardów DTV według klas wymienionych poniżej.

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

Od Androida 12 z Tuner HAL 1.1 lub nowszym obsługiwany jest następujący standard DTV.

  • DtmbFrontendSettings

Wartość FrontendCapabilities jest obliczana dla różnych standardów DTV na podstawie klas wymienionych poniżej.

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

Od Androida 12 z Tuner HAL 1.1 lub nowszym obsługiwany jest następujący standard DTV.

  • DtmbFrontendCapabilities

FrontendInfo pobiera informacje z interfejsu. FrontendStatus pobiera bieżący stan frontendu. OnTuneEventListener nasłuchuje zdarzeń na interfejsie. Aplikacja TIS używa usługi ScanCallback do przetwarzania wiadomości z skanowania z poziomu frontendu.

Skanowanie kanałów

Aby skonfigurować telewizor, aplikacja skanuje możliwe częstotliwości i tworzy listę kanałów, do których użytkownicy mają dostęp. TIS może używać Tuner.tune, Tuner.scan(BLIND_SCAN) lub Tuner.scan(AUTO_SCAN) do skanowania kanałów.

Jeśli TIS ma dokładne informacje o dostawie sygnału, takie jak częstotliwość, standard (np. T/T2, S/S2) i dodatkowe informacje (np. identyfikator PLD), zalecamy użycie opcji Tuner.tune, ponieważ jest ona szybsza.

Gdy użytkownik zadzwoni pod numer Tuner.tune, nastąpią te działania:

  • TIS wypełnia FrontendSettings wymaganymi informacjami za pomocą Tuner.tune.
  • Jeśli sygnał jest zablokowany, HAL zgłasza komunikaty dotyczące strojenia LOCKED.
  • TIS używa Frontend.getStatus do zbierania niezbędnych informacji.
  • TIS przechodzi do następnej dostępnej częstotliwości na liście częstotliwości.

TIS ponownie wywołuje Tuner.tune, aż wyczerpią się wszystkie częstotliwości.

Podczas strojenia możesz wybrać stopTune() lub close(), aby wstrzymać lub zakończyć połączenie Tuner.tune.

Tuner.scan(AUTO_SCAN)

Jeśli TIS nie ma wystarczającej ilości informacji do użycia Tuner.tune, ale ma listę częstotliwości i typ standardu (np. DVB T/C/S), zalecamy użycie Tuner.scan(AUTO_SCAN).

Gdy użytkownik zadzwoni pod numer Tuner.scan(AUTO_SCAN), nastąpią te działania:

  • TIS używa Tuner.scan(AUTO_SCAN)FrontendSettings wypełnionym częstotliwością.

  • Jeśli sygnał jest zablokowany, HAL zgłasza skanowanie wiadomości LOCKED. HAL może też przekazywać inne komunikaty skanowania, aby dostarczyć dodatkowych informacji o sygnale.

  • TIS używa Frontend.getStatus do zbierania niezbędnych informacji.

  • TIS wywołuje Tuner.scan, aby HAL kontynuował ustawienie następnego kanału na tej samej częstotliwości. Jeśli struktura FrontendSettings jest pusta, HAL używa następnego dostępnego ustawienia. W przeciwnym razie HAL używa FrontendSettings do jednorazowego skanowania i wysyła END, aby wskazać, że operacja skanowania została zakończona.

  • TIS powtarza te działania, dopóki nie wyczerpią się wszystkie ustawienia częstotliwości.

  • HAL wysyła END, aby wskazać, że operacja skanowania została zakończona.

  • TIS przechodzi do następnej dostępnej częstotliwości na liście częstotliwości.

TIS ponownie wywołuje Tuner.scan(AUTO_SCAN), aż wyczerpią się wszystkie częstotliwości.

Podczas skanowania możesz wywołać stopScan() lub close(), aby wstrzymać lub zakończyć skanowanie.

Tuner.scan(BLIND_SCAN)

Jeśli TIS nie ma listy częstotliwości, a interfejs HAL dostawcy może wyszukać częstotliwość interfejsu użytkownika, aby uzyskać zasób interfejsu, zalecamy użycie Tuner.scan(BLIND_SCAN).

  • TIS używa Tuner.scan(BLIND_SCAN). Częstotliwość rozpoczęcia można określić w parametrye FrontendSettings, ale TIS ignoruje inne ustawienia w parametrye FrontendSettings.
  • Jeśli sygnał jest zablokowany, HAL zgłasza skanowanie LOCKED.
  • TIS używa Frontend.getStatus do zbierania niezbędnych informacji.
  • TIS ponownie wywołuje Tuner.scan, aby kontynuować skanowanie. (wartość FrontendSettings jest ignorowana).
  • TIS powtarza te działania, dopóki nie wyczerpią się wszystkie ustawienia częstotliwości. HAL zwiększa częstotliwość bez konieczności podejmowania działań przez TIS. Raporty HALPROGRESS

TIS ponownie wywołuje Tuner.scan(AUTO_SCAN), aż wyczerpią się wszystkie częstotliwości. HAL zgłasza END, aby wskazać, że operacja skanowania została zakończona.

Podczas skanowania możesz wywołać stopScan() lub close(), aby wstrzymać lub zakończyć skanowanie.

Schemat blokowy procesu skanowania TIS

Rysunek 9. Schemat blokowy skanowania TIS

Android.media.tv.tuner.filter

Pakiet filtrów to zbiór operacji filtra wraz z konfiguracją, ustawieniami, wywołaniami zwrotnymi i zdarzeniami. Pakiet zawiera te operacje: Pełną listę operacji znajdziesz w źródełku Androida.

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

Pełną listę znajdziesz w kodzie źródłowym Androida.

FilterConfiguration pochodzi z klas wymienionych poniżej. Konfiguracje dotyczą głównego typu filtra i określają, którego protokołu używa filtr do wyodrębniania danych.

  • AlpFilterConfiguration
  • IpFilterConfiguration
  • MmtpFilterConfiguration
  • TlvFilterConfiguration
  • TsFilterConfiguration

Ustawienia pochodzą z klas wymienionych poniżej. Ustawienia te dotyczą podtypu filtra i określają, jakie dane może wykluczać.

  • SectionSettings
  • AvSettings
  • PesSettings
  • RecordSettings
  • DownloadSettings

FilterEvent pochodzi z klas wymienionych poniżej i służy do raportowania zdarzeń dotyczących różnych rodzajów danych.

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

Od Androida 12 z Tuner HAL 1.1 lub nowszym obsługiwane są te zdarzenia.

  • IpCidChangeEvent
  • RestartEvent
  • ScramblingStatusEvent
Format zdarzeń i danych z filtra
Typ filtra Flagi Wydarzenia Operacja na danych Format danych
TS.SECTION
MMTP.SECTION
IP.SECTION
TLV.SECTION
ALP.SECTION
isRaw:
true
Wymagane:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Zalecane:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Zgodnie z harmonogramem wydarzenia i harmonogramem wewnętrznym uruchom
Filter.read(buffer, offset, adjustedSize) co najmniej raz.

Dane są kopiowane z MQ HAL do bufora klienta.
Jeden z zmontowanych pakietów sesji jest wypełniany w FMQ przez inny pakiet sesji.
isRaw:
false
Wymagane:
DemuxFilterEvent::DemuxFilterSectionEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

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


Dane są kopiowane z MQ HAL do bufora klienta.
TS.PES isRaw:
true
Wymagane:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Zalecane:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Zgodnie z harmonogramem wydarzenia i harmonogramem wewnętrznym uruchom
Filter.read(buffer, offset, adjustedSize) co najmniej raz.

Dane są kopiowane z MQ HAL do bufora klienta.
Jeden zmontowany pakiet PES jest wypełniany w FMQ przez inny pakiet PES.
isRaw:
false
Wymagane:
DemuxFilterEvent::DemuxFilterPesEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

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


Dane są kopiowane z MQ HAL do bufora klienta.
MMTP.PES isRaw:
true
Wymagane:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Zalecane:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Zgodnie z harmonogramem wydarzenia i harmonogramem wewnętrznym uruchom
Filter.read(buffer, offset, adjustedSize) co najmniej raz.

Dane są kopiowane z MQ HAL do bufora klienta.
Jeden zmontowany pakiet MFU jest wypełniany w FMQ przez inny pakiet MFU.
isRaw:
false
Wymagane:
DemuxFilterEvent::DemuxFilterPesEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

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


Dane są kopiowane z MQ HAL do bufora klienta.
TS.TS
Nie dotyczy Wymagane:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Zalecane:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Zgodnie z harmonogramem wydarzenia i harmonogramem wewnętrznym uruchom
Filter.read(buffer, offset, adjustedSize) co najmniej raz.

Dane są kopiowane z MQ HAL do bufora klienta.
Odfiltrowane ts z nagłówkiem ts
jest wypełnione w FMQ.
TS.Audio
TS.Video
MMTP.Audio
MMTP.Video
isPassthrough:
true
Opcjonalnie:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
Klient może rozpocząć MediaCodec po otrzymaniu DemuxFilterStatus::DATA_READY.
Po otrzymaniu wiadomości DemuxFilterStatus::DATA_OVERFLOW klient może zadzwonić pod numer Filter.flush.
Nie dotyczy
isPassthrough:
false
Wymagane:
DemuxFilterEvent::DemuxFilterMediaEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Opcjonalnie:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Aby użyć MediaCodec:
for i=0; i<n; i++
linearblock = MediaEvent[i].getLinearBlock();
codec.startQueueLinearBlock(linearblock)
linearblock.recycle()


Aby użyć Direct Audio z AudioTrack:
for i=0; i<n; i++
audioHandle = MediaEvent[i].getAudioHandle();
audiotrack.write(encapsulated(audiohandle))
ES lub częściowe dane ES w pamięci ION.
TS.PCR
IP.NTP
ALP.PTP
Nie dotyczy Wymagany: nie dotyczy
Opcjonalny: nie dotyczy
Nie dotyczy Nie dotyczy
TS.RECORD Nie dotyczy Wymagane:
DemuxFilterEvent::DemuxFilterTsRecordEvent[n]
RecordStatus::DATA_READY
RecordStatus::DATA_OVERFLOW
RecordStatus::LOW_WATER
RecordStatus::HIGH_WATER

Opcjonalnie:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Dane indeksu:
for i=0; i<n; i++
DemuxFilterTsRecordEvent[i];


W przypadku nagranych treści: zgodnie z RecordStatus::* i harmonogramem wewnętrznym wykonaj jedną z tych czynności:
  • Uruchom DvrRecord.write(adustedSize)co najmniej raz w chmurze.
    Dane są przenoszone z MQ HAL do pamięci masowej.
  • Uruchom DvrRecord.write(buffer, adustedSize)kilka razy, aby przepuścić dane przez bufor.
    Dane są kopiowane z MQ HAL do bufora klienta.
Dane indeksu: są przenoszone w ładunku zdarzenia.

W przypadku treści nagranych: strumień TS zmiksowany wypełniony w FMQ.
TS.TEMI Nie dotyczy Wymagane:
DemuxFilterEvent::DemuxFilterTemiEvent[n]

Opcjonalnie:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
for i=0; i<n; i++
DemuxFilterTemiEvent[i];
Nie dotyczy
MMTP.MMTP Nie dotyczy Wymagane:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Zalecane:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Zgodnie z harmonogramem wydarzenia i harmonogramem wewnętrznym uruchom
Filter.read(buffer, offset, adjustedSize) co najmniej raz.

Dane są kopiowane z MQ HAL do bufora klienta.
Odfiltrowane mmtp z nagłówkiem mmtp
jest wypełnione w FMQ.
MMTP.RECORD Nie dotyczy Wymagane:
DemuxFilterEvent::DemuxFilterMmtpRecordEvent[n]
RecordStatus::DATA_READY
RecordStatus::DATA_OVERFLOW
RecordStatus::LOW_WATER
RecordStatus::HIGH_WATER

Opcjonalnie:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Dane indeksu: for i=0; i<n; i++
DemuxFilterMmtpRecordEvent[i];


W przypadku nagranych treści zgodnie z RecordStatus::* i harmonogramem wewnętrznym wykonaj jedną z tych czynności:
  • Uruchom DvrRecord.write(adjustedSize) co najmniej raz, aby zapisać dane w miejscu do przechowywania.
    Dane są przenoszone z MQ HAL do pamięci masowej.
  • Uruchom DvrRecord.write(buffer, adjustedSize)co najmniej raz, aby przetworzyć dane w buforze.
    Dane są kopiowane z MQ HAL do bufora klienta.
Dane indeksu: są przenoszone w ładunku zdarzenia.

W przypadku treści nagranych: zmiksowany strumień nagrania wypełniony w FMQ.

Jeśli źródło filtra do nagrywania to TLV.TLV do IP.IP z przepuszczaniem, nagrany strumień zawiera nagłówek TLV i IP.
MMTP.DOWNLOAD Nie dotyczy Wymagane:
DemuxFilterEvent::DemuxFilterDownloadEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

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

Dane są kopiowane z MQ HAL do bufora klienta.
Pakiet pobierania jest wypełniany w FMQ przez inny pakiet pobierania IP.
IP.IP_PAYLOAD Nie dotyczy Wymagane:
DemuxFilterEvent::DemuxFilterIpPayloadEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

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

Dane są kopiowane z MQ HAL do bufora klienta.
Pakiet danych IP jest wypełniany w FMQ przez inny pakiet danych IP.
IP.IP
TLV.TLV
ALP.ALP
isPassthrough:
true
Opcjonalnie:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
Filtrowany podstrumień protokołu przekazuje dane do następnego filtra w łańcuchu filtrów. Nie dotyczy
isPassthrough:
false
Wymagane:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

Zalecane:
DemuxFilterStatus::LOW_WATER
DemuxFilterStatus::HIGH_WATER
Zgodnie z harmonogramem wydarzenia i harmonogramem wewnętrznym uruchom
Filter.read(buffer, offset, adjustedSize) co najmniej raz.

Dane są kopiowane z MQ HAL do bufora klienta.
Filtrowany podstrumień protokołu z nagłówkiem protokołu jest wypełniany w FMQ.
IP.PAYLOAD_THROUGH
TLV.PAYLOAD_THROUGH
ALP.PAYLOAD_THROUGH
Nie dotyczy Opcjonalnie:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
Odfiltrowany ładunek protokołu przekazuje dane następnemu filtrowi w łańcuchu filtrów. Nie dotyczy
Przykładowy proces tworzenia PSI/SI za pomocą filtra

Przykładowy proces tworzenia PSI/SI za pomocą filtra

Rysunek 10. Proces tworzenia PSI/SI

  1. Otwórz filtr.

    Filter filter = tuner.openFilter(
      Filter.TYPE_TS,
      Filter.SUBTYPE_SECTION,
      /* bufferSize */1000,
      executor,
      filterCallback
    );
    
  2. Skonfiguruj i uruchom filtr.

    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. Przetwarzam 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); }
          }
        }
    };
    
Przykładowy sposób korzystania z MediaEvent z filtra

Przykładowy przepływ danych, w którym używany jest filtr MediaEvent.

Rysunek 11. Sposób używania filtra MediaEvent

  1. Otwórz, skonfiguruj i uruchom filtry A/V.
  2. Przetwarzam MediaEvent.
  3. Odbieranie MediaEvent.
  4. Umieść blok liniowy w kolejce do codec.
  5. Po wykorzystaniu danych zwalniaj uchwyt A/V.

Android.media.tv.tuner.dvr

DvrRecorder udostępnia te metody nagrywania.

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

DvrPlayback udostępnia te metody odtwarzania.

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

Wartość DvrSettings służy do konfigurowania wartości DvrRecorderDvrPlayback. Wartości OnPlaybackStatusChangedListenerOnRecordStatusChangedListener służą do raportowania stanu wystąpienia DVR.

Przykładowy przepływ pracy, aby rozpocząć nagrywanie

Przykładowy proces rozpoczęcia nagrywania.

Rysunek 12. Procedura rozpoczęcia nagrywania

  1. Otwórz, skonfiguruj i uruchom 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. Otrzymaj RecordEvent i pobierz informacje indeksu.

    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. Inicjowanie OnRecordStatusChangedListener i przechowywanie danych rekordu.

      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

Interfejs HAL tunera jest zgodny z HIDL i określa interfejs między frameworkem a sprzętem dostawcy. Dostawcy używają tego interfejsu do implementowania Tunera HAL, a ramka używa go do komunikacji z implementacją Tunera HAL.

Moduły

Tuner HAL 1.0

Moduły Podstawowe funkcje sterowania Ustawienia dotyczące poszczególnych modułów Pliki HAL
ITuner Nie dotyczy 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 (wyprowadzony z Tuner HAL 1.0)

Moduły Podstawowe funkcje sterowania Ustawienia dotyczące poszczególnych modułów Pliki HAL
ITuner Nie dotyczy 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

Schemat blokowy interakcji między modułami tunera HAL.

Rysunek 13. Schemat interakcji między modułami HAL tunera

Filtrowanie połączeń

Tuner HAL obsługuje łączenie filtrów, dzięki czemu filtry można łączyć z innymi filtrami w wielu warstwach. Filtry działają zgodnie z podanymi niżej zasadami.

  • Filtry są połączone w drzewo, więc nie można stosować ścieżki zamykania.
  • Węzłem głównym jest demux.
  • Filtry działają niezależnie.
  • Wszystkie filtry zaczynają pobierać dane.
  • Powiązanie filtrów jest opróżniane w ostatnim filtrze.

Poniżej znajduje się blok kodu, a na rysunku 14 widać przykład filtrowania wielu warstw.

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>)
}

Diagram przykładowego powiązania filtrów

Rysunek 14. Schemat działania połączenia filtra w przypadku wielu warstw

Menedżer zasobów tunera

Przed wprowadzeniem Menedżera zasobów tunera (TRM) przełączanie się między 2 aplikacjami wymagało korzystania z tego samego sprzętu tunera. Ramy danych wejściowych TV (TIF) używały mechanizmu „pierwszy lepszy”, co oznacza, że aplikacja, która jako pierwsza uzyskała zasób, zatrzymuje go. Ten mechanizm może jednak nie być odpowiedni w przypadku niektórych skomplikowanych przypadków użycia.

TRM działa jako usługa systemowa, która zarządza zasobami sprzętowymi tunera, TVInput i CAS dla aplikacji. TRM korzysta z mechanizmu „wygrywania na pierwszym planie”, który oblicza priorytet aplikacji na podstawie jej stanu (czy jest na pierwszym planie czy w tle) oraz typu przypadku użycia. TRM przyznaje lub odwołuje zasób na podstawie priorytetu. TRM centralizuje zarządzanie zasobami ATV na potrzeby transmisji, OTT i DVR.

Interfejs TRM

TRM udostępnia interfejsy AIDL w ITunerResourceManager.aidl dla frameworku Tuner, MediaCasTvInputHardwareManager w celu rejestrowania, żądania lub uwalniania zasobów.

Interfejsy do zarządzania klientami:

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

Poniżej znajdziesz interfejsy do żądania i zwalniania zasobów.

  • 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

Klasy klientów i żądań znajdziesz poniżej.

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

Priorytet klienta

TRM oblicza priorytet klienta na podstawie parametrów z jego profilu i wartości priorytetu z pliku konfiguracyjnego. Priorytet może też być aktualizowany przez dowolną wartość priorytetu z klienta.

Parametry w profilu klienta

TRM pobiera identyfikator procesu z mTvInputSessionId, aby określić, czy aplikacja jest na pierwszym czy drugim planie. Aby utworzyć mTvInputSessionId, TvInputService.onCreateSession lub TvInputService.onCreateRecordingSession, inicjuje sesję TIS.

mUseCase oznacza przypadek użycia sesji. Poniżej znajdziesz listę wstępnie zdefiniowanych zastosowań.

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
}

Plik konfiguracji

Domyślny plik konfiguracji

Poniżej znajduje się domyślny plik konfiguracji zawierający wartości priorytetów dla zdefiniowanych wstępnie przypadków użycia. Użytkownicy mogą zmieniać te wartości za pomocą spersonalizowanego pliku konfiguracji.

Przypadek użycia Pierwszy plan Tło
LIVE 490 400
PLAYBACK 480 300
RECORD 600 500
SCAN 450 200
BACKGROUND 180 100
Niestandardowy plik konfiguracji

Dostawcy mogą dostosowywać plik konfiguracji./vendor/etc/tunerResourceManagerUseCaseConfig.xml Ten plik służy do dodawania, usuwania i aktualizowania typów przypadków użycia oraz wartości priorytetów przypadków użycia. Dostosowany plik może używać platform/hardware/interfaces/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml jako szablonu.

Przykładem zastosowania dla nowego dostawcy jest VENDOR_USE_CASE__[A-Z0-9]+, [0 - 1000]. Format powinien być zgodny z platform/hardware/interfaces/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfig.xsd.

dowolna wartość priorytetu i przyjazna wartość

TRM udostępnia klientowi element updateClientPriority, który umożliwia mu zaktualizowanie dowolnej wartości priorytetu i wartości wyświetlanej. Wartość dowolnego priorytetu zastępuje wartość priorytetu obliczoną na podstawie typu przypadku użycia i identyfikatora sesji.

Wartość nice wskazuje, jak łagodne jest zachowanie klienta, gdy wchodzi on w konflikt z innym klientem. Wartość nice zmniejsza priorytet klienta przed porównaniem jego wartości priorytetu z wartością trudnego klienta.

Mechanizm odzyskiwania

Diagram poniżej pokazuje, jak zasoby są odzyskiwane i przypisywane, gdy wystąpi konflikt zasobów.

Schemat mechanizmu odzyskiwania

Rysunek 15. Schemat mechanizmu odzyskiwania zasobów w przypadku konfliktu między zasobami tunera