Para Android 11 ou superior, você pode usar a estrutura Android Tuner para fornecer conteúdo A/V. A estrutura usa o pipeline de hardware dos fornecedores, tornando-a adequada tanto para SoC de baixo quanto de alto nível. A estrutura fornece uma maneira segura de fornecer conteúdo A/V protegido por um ambiente de execução confiável (TEE) e um caminho de mídia seguro (SMP), permitindo que ele seja usado em um ambiente de proteção de conteúdo altamente restrito.
A interface padronizada entre o Tuner e o Android CAS resulta em uma integração mais rápida entre os fornecedores do Tuner e os fornecedores do CAS. A interface do Tuner funciona com MediaCodec
e AudioTrack
para construir uma solução mundial para Android TV. A interface do sintonizador suporta TV digital e TV analógica com base nos principais padrões de transmissão.
Componentes
Para o Android 11, três componentes foram projetados especificamente para a plataforma de TV.
- Tuner HAL: uma interface entre a estrutura e os fornecedores
- API Tuner SDK: uma interface entre a estrutura e os aplicativos
- Tuner Resource Manager (TRM): Coordena os recursos de HW do Tuner
Para o Android 11, os seguintes componentes foram aprimorados.
- CAS V2
-
TvInputService
ou serviço de entrada de TV (TIS) -
TvInputManagerService
ou serviço gerenciador de entrada de TV (TIMS) -
MediaCodec
ou codec de mídia -
AudioTrack
ou trilha de áudio -
MediaResourceManager
ou gerenciador de recursos de mídia (MRM)
Figura 1. Interações entre componentes do Android TV
Características
O frontend suporta os padrões DTV abaixo.
- ATSC
- ATSC3
- DVB C/S/T
- ISDB S/S3/T
- Analógico
O front-end no Android 12 com Tuner HAL 1.1 ou superior oferece suporte ao padrão DTV abaixo.
- DTMB
Demux suporta os protocolos de stream abaixo.
- Fluxo de transporte (TS)
- Protocolo de transporte de mídia MPEG (MMTP)
- Protocolo de Internet (IP)
- Digite o valor do comprimento (TLV)
- Protocolo de camada de link ATSC (ALP)
O Descrambler oferece suporte às proteções de conteúdo abaixo.
- Caminho de mídia seguro
- Limpar caminho de mídia
- Registro local seguro
- Reprodução local segura
As APIs do sintonizador oferecem suporte aos casos de uso abaixo.
- Varredura
- Ao vivo
- Reprodução
- Registro
Tuner, MediaCodec
e AudioTrack
suportam os modos de fluxo de dados abaixo.
- Carga ES com buffer de memória limpo
- Carga ES com identificador de memória seguro
- Atravessar
Design geral
O Tuner HAL é definido entre a estrutura do Android e o hardware do fornecedor.
- Descreve o que a estrutura espera do fornecedor e como o fornecedor pode fazer isso.
- Exporta as funcionalidades de frontend, demux e descrambler para o framework através das interfaces
IFrontend
,IDemux
,IDescrambler
,IFilter
,IDvr
eILnb
. - Inclui as funções para integrar o Tuner HAL com outros componentes do framework, como
MediaCodec
eAudioTrack
.
Uma classe Tuner Java e uma classe nativa são criadas.
- A API Tuner Java permite que os aplicativos acessem o Tuner HAL por meio de APIs públicas.
- A classe nativa permite controle de permissão e manipulação de grandes quantidades de dados de gravação ou reprodução com o Tuner HAL.
- O módulo Native Tuner é uma ponte entre a classe Tuner Java e o Tuner HAL.
Uma classe TRM é criada.
- Gerencia recursos limitados do sintonizador, como frontend, LNB, sessões CAS e um dispositivo de entrada de TV a partir do HAL de entrada de TV.
- Aplica regras para recuperar recursos insuficientes de aplicativos. A regra padrão é a vitória em primeiro plano.
Media CAS e CAS HAL são aprimorados com os recursos abaixo.
- Abre sessões CAS para diferentes usos e algoritmos.
- Suporta sistemas CAS dinâmicos, como remoção e inserção de CICAM.
- Integra-se ao Tuner HAL fornecendo tokens de chave.
MediaCodec
e AudioTrack
são aprimorados com os recursos abaixo.
- Utiliza memória A/V segura como entrada de conteúdo.
- Configurado para fazer sincronização A/V de hardware na reprodução em túnel.
- Suporte configurado para
ES_payload
e modo passthrough.
Figura 2. Diagrama dos componentes do sintonizador HAL
Fluxo de trabalho geral
Os diagramas abaixo ilustram sequências de chamadas para reprodução de transmissão ao vivo.
Configurar
Figura 3. Sequência de configuração para reprodução de transmissão ao vivo
Tratamento de A/V
Figura 4. Tratamento de A/V para reprodução de transmissão ao vivo
Lidando com conteúdo embaralhado
Figura 5. Tratamento de conteúdo criptografado para reprodução de transmissão ao vivo
Processando dados A/V
Figura 6. Processamento A/V para reprodução de transmissão ao vivo
API do SDK do sintonizador
A API Tuner SDK lida com as interações com o Tuner JNI, o Tuner HAL e TunerResourceManager
. O aplicativo TIS usa a API Tuner SDK para acessar recursos e subcomponentes do Tuner, como filtro e decodificador. Frontend e demux são componentes internos.
Figura 7. Interações com a API Tuner SDK
Versões
A partir do Android 12, a API Tuner SDK oferece suporte a novos recursos no Tuner HAL 1.1, que é uma atualização de versão compatível com versões anteriores do Tuner 1.0.
Use a API a seguir para verificar a versão do HAL em execução.
-
android.media.tv.tuner.TunerVersionChecker.getTunerVersion()
A versão HAL mínima exigida pode ser encontrada na documentação das novas APIs do Android 12.
Pacotes
A API Tuner SDK fornece os quatro pacotes abaixo.
-
android.media.tv.tuner
-
android.media.tv.tuner.frontend
-
android.media.tv.tuner.filter
-
android.media.tv.tuner.dvr
Figura 8. Pacotes de API do Tuner SDK
Android.media.tv.tuner
O pacote Tuner é um ponto de entrada para usar a estrutura Tuner. O aplicativo TIS usa o pacote para inicializar e adquirir instâncias de recursos especificando a configuração inicial e o retorno de chamada.
-
tuner()
: inicializa uma instância do Tuner especificando os parâmetrosuseCase
esessionId
. -
tune()
: adquire um recurso de frontend e ajusta especificando o parâmetroFrontendSetting
. -
openFilter()
: adquire uma instância de filtro especificando o tipo de filtro. -
openDvrRecorder()
: adquire uma instância de gravação especificando o tamanho do buffer. -
openDvrPlayback()
: adquire uma instância de reprodução especificando o tamanho do buffer. -
openDescrambler()
: Adquire uma instância do descrambler. -
openLnb()
: Adquire uma instância interna do LNB. -
openLnbByName()
: Adquire uma instância externa do LNB. -
openTimeFilter()
: adquire uma instância de filtro de tempo.
O pacote Tuner fornece funcionalidades que não são cobertas pelos pacotes de filtro, DVR e frontend. As funcionalidades estão listadas abaixo.
-
cancelTuning
-
scan
/cancelScanning
-
getAvSyncHwId
-
getAvSyncTime
-
connectCiCam1
/disconnectCiCam
-
shareFrontendFromTuner
-
updateResourcePriority
-
setOnTuneEventListener
-
setResourceLostListener
Android.media.tv.tuner.frontend
O pacote frontend inclui coleções de configurações, informações, status, eventos e recursos relacionados ao frontend.
Aulas
FrontendSettings
é derivado para diferentes padrões de DTV pelas classes abaixo.
-
AnalogFrontendSettings
-
Atsc3FrontendSettings
-
AtscFrontendSettings
-
DvbcFrontendSettings
-
DvbsFrontendSettings
-
DvbtFrontendSettings
-
Isdbs3FrontendSettings
-
IsdbsFrontendSettings
-
IsdbtFrontendSettings
A partir do Android 12 com sintonizador HAL 1.1 ou superior, o seguinte padrão DTV é compatível.
-
DtmbFrontendSettings
FrontendCapabilities
é derivado para diferentes padrões de DTV pelas classes abaixo.
-
AnalogFrontendCapabilities
-
Atsc3FrontendCapabilities
-
AtscFrontendCapabilities
-
DvbcFrontendCapabilities
-
DvbsFrontendCapabilities
-
DvbtFrontendCapabilities
-
Isdbs3FrontendCapabilities
-
IsdbsFrontendCapabilities
-
IsdbtFrontendCapabilities
A partir do Android 12 com sintonizador HAL 1.1 ou superior, o seguinte padrão DTV é compatível.
-
DtmbFrontendCapabilities
FrontendInfo
recupera as informações do frontend. FrontendStatus
recupera o status atual do frontend. OnTuneEventListener
escuta os eventos no frontend. O aplicativo TIS usa ScanCallback
para processar mensagens de verificação do frontend.
Varredura de canal
Para configurar uma TV, o aplicativo verifica possíveis frequências e cria uma programação de canais para os usuários acessarem. O TIS pode usar Tuner.tune
, Tuner.scan(BLIND_SCAN)
ou Tuner.scan(AUTO_SCAN)
para concluir a varredura de canal.
Se o TIS tiver informações precisas de entrega do sinal, como frequência, padrão (por exemplo, T/T2, S/S2) e informações adicionais necessárias (por exemplo, PLD ID), então Tuner.tune
é recomendado como a opção mais rápida .
Quando o usuário chama Tuner.tune
, acontecem as seguintes ações:
- O TIS preenche
FrontendSettings
com as informações necessárias usandoTuner.tune
. - Os relatórios HAL sintonizam mensagens
LOCKED
se o sinal estiver bloqueado. - O TIS usa
Frontend.getStatus
para coletar as informações necessárias. - O TIS passa para a próxima frequência disponível na sua lista de frequências.
O TIS chama Tuner.tune
novamente até que todas as frequências se esgotem.
Durante a sintonia, você pode chamar stopTune()
ou close()
para pausar ou encerrar a chamada Tuner.tune
.
Tuner.scan(AUTO_SCAN)
Se o TIS não tiver informações suficientes para usar Tuner.tune
, mas tiver uma lista de frequências e um tipo padrão (por exemplo, DVB T/C/S), então Tuner.scan(AUTO_SCAN)
é recomendado.
Quando o usuário chama Tuner.scan(AUTO_SCAN)
, as seguintes ações acontecem:
O TIS usa
Tuner.scan(AUTO_SCAN)
comFrontendSettings
preenchido com frequência.Os relatórios HAL verificam mensagens
LOCKED
se o sinal estiver bloqueado. O HAL também pode reportar outras mensagens de varredura para fornecer informações adicionais sobre o sinal.O TIS usa
Frontend.getStatus
para coletar as informações necessárias.O TIS chama
Tuner.scan
para que o HAL continue para a próxima configuração na mesma frequência. Se a estruturaFrontendSettings
estiver vazia, o HAL usará a próxima configuração disponível. Caso contrário, HAL usaFrontendSettings
para uma verificação única e enviaEND
para indicar que a operação de verificação foi concluída.O TIS repete as ações acima até que todas as configurações da frequência sejam esgotadas.
O HAL envia
END
para indicar que a operação de varredura foi concluída.O TIS passa para a próxima frequência disponível na sua lista de frequências.
O TIS chama Tuner.scan(AUTO_SCAN)
novamente até que todas as frequências se esgotem.
Durante a varredura, você pode chamar stopScan()
ou close()
para pausar ou encerrar a varredura.
Tuner.scan(BLIND_SCAN)
Se o TIS não tiver uma lista de frequências e o fornecedor HAL puder procurar a frequência do front-end especificado pelo usuário para obter o recurso de front-end, então Tuner.scan(BLIND_SCAN)
é recomendado.
- O TIS usa
Tuner.scan(BLIND_SCAN)
. Uma frequência pode ser especificada emFrontendSettings
para frequência inicial, mas o TIS ignora outras configurações emFrontendSettings
. - O HAL reporta uma mensagem scan
LOCKED
se o sinal estiver bloqueado. - O TIS usa
Frontend.getStatus
para coletar as informações necessárias. - O TIS chama
Tuner.scan
novamente para continuar a digitalização. (FrontendSettings
é ignorado.) - O TIS repete as ações acima até que todas as configurações da frequência sejam esgotadas. O HAL aumenta a frequência sem nenhuma ação necessária do TIS. O HAL relata
PROGRESS
.
O TIS chama Tuner.scan(AUTO_SCAN)
novamente até que todas as frequências se esgotem. O HAL informa END
para indicar que a operação de varredura foi concluída.
Durante a varredura, você pode chamar stopScan()
ou close()
para pausar ou encerrar a varredura.
Figura 9. Diagrama de fluxo de uma varredura TIS
Android.media.tv.tuner.filter
O pacote de filtros é uma coleção de operações de filtro junto com configurações, definições, retornos de chamada e eventos. O pacote inclui as operações abaixo. Consulte o código-fonte do Android para obter a lista completa de operações.
-
configure()
-
start()
-
stop()
-
flush()
-
read()
Consulte o código-fonte do Android para obter a lista completa.
FilterConfiguration
é derivado das classes abaixo. As configurações são para o tipo de filtro principal e especificam qual protocolo o filtro usa para extrair dados.
-
AlpFilterConfiguration
-
IpFilterConfiguration
-
MmtpFilterConfiguration
-
TlvFilterConfiguration
-
TsFilterConfiguration
As configurações são derivadas das classes abaixo. As configurações são para o subtipo de filtro e especificam quais tipos de dados o filtro pode excluir.
-
SectionSettings
-
AvSettings
-
PesSettings
-
RecordSettings
-
DownloadSettings
FilterEvent
é derivado das classes abaixo para relatar eventos para diferentes tipos de dados.
-
SectionEvent
-
MediaEvent
-
PesEvent
-
TsRecordEvent
-
MmtpRecordEvent
-
TemiEvent
-
DownloadEvent
-
IpPayloadEvent
A partir do Android 12 com Tuner HAL 1.1 ou superior, os seguintes eventos são suportados.
-
IpCidChangeEvent
-
RestartEvent
-
ScramblingStatusEvent
Eventos e formato de dados do filtro
Tipo de filtro | Bandeiras | Eventos | Operação de dados | Formato de dados |
---|---|---|---|---|
TS.SECTION MMTP.SECTION IP.SECTION TLV.SECTION ALP.SECTION | isRaw: | Obrigatório:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Recomendado: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | De acordo com o evento e programação interna, executeFilter.read(buffer, offset, adjustedSize) uma ou mais vezes.Os dados são copiados do MQ do HAL para o buffer do cliente. | Um pacote de sessão montado é preenchido no FMQ por outro pacote de sessão. |
isRaw: | Obrigatório:DemuxFilterEvent::DemuxFilterSectionEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Opcional: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | for i=0; i<n; i++ Os dados são copiados do MQ do HAL para o buffer do cliente. | ||
TS.PES | isRaw: | Obrigatório:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Recomendado: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | De acordo com o evento e programação interna, executeFilter.read(buffer, offset, adjustedSize) uma ou mais vezes.Os dados são copiados do MQ do HAL para o buffer do cliente. | Um pacote PES montado é preenchido no FMQ por outro pacote PES. |
isRaw: | Obrigatório:DemuxFilterEvent::DemuxFilterPesEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Opcional: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | for i=0; i<n; i++ Os dados são copiados do MQ do HAL para o buffer do cliente. | ||
MMTP.PES | isRaw: | Obrigatório:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Recomendado: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | De acordo com o evento e programação interna, executeFilter.read(buffer, offset, adjustedSize) uma ou mais vezes.Os dados são copiados do MQ do HAL para o buffer do cliente. | Um pacote MFU montado é preenchido no FMQ por outro pacote MFU. |
isRaw: | Obrigatório:DemuxFilterEvent::DemuxFilterPesEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Opcional: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | for i=0; i<n; i++ Os dados são copiados do MQ do HAL para o buffer do cliente. | ||
TS.TS | N / D | Obrigatório:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Recomendado: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | De acordo com o evento e programação interna, executeFilter.read(buffer, offset, adjustedSize) uma ou mais vezes.Os dados são copiados do MQ do HAL para o buffer do cliente. | Filtrado ts com cabeçalho ts é preenchido no FMQ. |
TS.Audio TS.Video MMTP.Audio MMTP.Video | isPassthrough: | Opcional:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW | O cliente pode iniciar MediaCodec após receber DemuxFilterStatus::DATA_READY .O cliente pode chamar Filter.flush após receber DemuxFilterStatus::DATA_OVERFLOW . | N / D |
isPassthrough: | Obrigatório:DemuxFilterEvent::DemuxFilterMediaEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Opcional: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | Para usar MediaCodec :for i=0; i<n; i++ Para usar o áudio direto do AudioTrack :for i=0; i<n; i++ | Dados ES ou ES parciais na memória ION. | |
TS.PCR IP.NTP ALP.PTP | N / D | Obrigatório: N/A Opcional: N/A | N / D | N / D |
TS.RECORD | N / D | Obrigatório:DemuxFilterEvent::DemuxFilterTsRecordEvent[n] RecordStatus::DATA_READY RecordStatus::DATA_OVERFLOW RecordStatus::LOW_WATER RecordStatus::HIGH_WATER Opcional: DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | Para dados de índice:for i=0; i<n; i++ Para conteúdo gravado , de acordo com RecordStatus::* e programação interna, siga um destes procedimentos:
| Para dados de índice: transportados na carga útil do evento. Para conteúdo gravado: Stream Muxed TS preenchido em FMQ. |
TS.TEMI | N / D | Obrigatório:DemuxFilterEvent::DemuxFilterTemiEvent[n] Opcional: DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | for i=0; i<n; i++ | N / D |
MMTP.MMTP | N / D | Obrigatório:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Recomendado: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | De acordo com o evento e programação interna, executeFilter.read(buffer, offset, adjustedSize) uma ou mais vezes.Os dados são copiados do MQ do HAL para o buffer do cliente. | Filtrado mmtp com cabeçalho mmtp é preenchido no FMQ. |
MMTP.RECORD | N / D | Obrigatório:DemuxFilterEvent::DemuxFilterMmtpRecordEvent[n] RecordStatus::DATA_READY RecordStatus::DATA_OVERFLOW RecordStatus::LOW_WATER RecordStatus::HIGH_WATER Opcional: DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | Para dados de índice: for i=0; i<n; i++ Para conteúdo gravado , de acordo com RecordStatus::* e programação interna, siga um destes procedimentos:
| Para dados de índice: transportados na carga útil do evento. Para conteúdo gravado: Stream gravado com mux preenchido em FMQ. Se a origem do filtro para gravação for TLV.TLV para IP.IP com passagem, o fluxo gravado terá um cabeçalho TLV e IP. |
MMTP.DOWNLOAD | N / D | Obrigatório:DemuxFilterEvent::DemuxFilterDownloadEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Opcional: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | for i=0; i<n; i++ Filter.read(buffer, offset, DemuxFilterDownloadEvent[i].size) Os dados são copiados do MQ do HAL para o buffer do cliente. | O pacote de download é preenchido no FMQ por outro pacote de download IP. |
IP.IP_PAYLOAD | N / D | Obrigatório:DemuxFilterEvent::DemuxFilterIpPayloadEvent[n] DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Opcional: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | for i=0; i<n; i++ Filter.read(buffer, offset, DemuxFilterIpPayloadEvent[i].size) Os dados são copiados do MQ do HAL para o buffer do cliente. | O pacote de carga útil IP é preenchido no FMQ por outro pacote de carga útil IP. |
IP.IP TLV.TLV ALP.ALP | isPassthrough: | Opcional:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW | O subfluxo de protocolo filtrado alimenta o próximo filtro na cadeia de filtros. | N / D |
isPassthrough: | Obrigatório:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Recomendado: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::HIGH_WATER | De acordo com o evento e programação interna, executeFilter.read(buffer, offset, adjustedSize) uma ou mais vezes.Os dados são copiados do MQ do HAL para o buffer do cliente. | O subfluxo de protocolo filtrado com cabeçalho de protocolo é preenchido no FMQ. | |
IP.PAYLOAD_THROUGH TLV.PAYLOAD_THROUGH ALP.PAYLOAD_THROUGH | N / D | Opcional:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW | A carga útil do protocolo filtrada alimenta o próximo filtro na cadeia de filtros. | N / D |
Fluxo de exemplo para usar filtro para construir PSI/SI
Figura 10. Fluxo para construir PSI/SI
Abra um filtro.
Filter filter = tuner.openFilter( Filter.TYPE_TS, Filter.SUBTYPE_SECTION, /* bufferSize */1000, executor, filterCallback );
Configure e inicie o filtro.
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();
Processar
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); } } } };
Fluxo de exemplo para usar MediaEvent do filtro
Figura 11. Fluxo para usar MediaEvent do filtro
- Abra, configure e inicie os filtros A/V.
- Processar
MediaEvent
. - Receba
MediaEvent
. - Coloque o bloco linear na
codec
. - Solte o identificador A/V quando os dados forem consumidos.
Android.media.tv.tuner.dvr
DvrRecorder
fornece esses métodos para gravação.
-
configure
-
attachFilter
-
detachFilter
-
start
-
flush
-
stop
-
setFileDescriptor
-
write
DvrPlayback
fornece esses métodos para reprodução.
-
configure
-
start
-
flush
-
stop
-
setFileDescriptor
-
read
DvrSettings
é usado para configurar DvrRecorder
e DvrPlayback
. OnPlaybackStatusChangedListener
e OnRecordStatusChangedListener
são usados para relatar o status de uma instância de DVR.
Fluxo de exemplo para iniciar um registro
Figura 12. Fluxo para iniciar um registro
Abra, configure e inicie
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();
Receba
RecordEvent
e recupere as informações do índice.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. } } } };
Inicialize
OnRecordStatusChangedListener
e armazene os dados do registro.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); } } };
Sintonizador HAL
O Tuner HAL segue o HIDL e define a interface entre a estrutura e o hardware do fornecedor. Os fornecedores usam a interface para implementar o Tuner HAL e a estrutura a utiliza para se comunicar com a implementação do Tuner HAL.
Módulos
Sintonizador HAL 1.0
Módulos | Controles básicos | Controles específicos do módulo | Arquivos HAL |
---|---|---|---|
ITuner | N / D | 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 |
Sintonizador HAL 1.1 (derivado do sintonizador HAL 1.0)
Módulos | Controles básicos | Controles específicos do módulo | Arquivos HAL |
---|---|---|---|
ITuner | N / D | 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 |
Figura 13. Diagrama das interações entre os módulos Tuner HAL
Vinculação de filtro
O Tuner HAL oferece suporte à ligação de filtros de forma que os filtros possam ser vinculados a outros filtros para múltiplas camadas. Os filtros seguem as regras abaixo.
- Os filtros são vinculados como uma árvore, o caminho próximo não é permitido.
- O nó raiz é demux.
- Os filtros operam de forma independente.
- Todos os filtros começam a obter dados.
- A ligação do filtro descarrega no último filtro.
O bloco de código abaixo e a Figura 14 ilustram um exemplo de filtragem de múltiplas camadas.
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>)
}
Figura 14. Diagrama de fluxo de uma ligação de filtro para múltiplas camadas
Gerenciador de recursos do sintonizador
Antes do Tuner Resource Manager (TRM), alternar entre dois aplicativos exigia o mesmo hardware do Tuner. O TV Input Framework (TIF) usou um mecanismo de “vitória do primeiro a adquirir”, o que significa que o aplicativo que obtiver o recurso primeiro o manterá. No entanto, este mecanismo pode não ser ideal para alguns casos de uso complicados.
O TRM é executado como um serviço de sistema para gerenciar os recursos de hardware Tuner, TVInput
e CAS para aplicativos. O TRM usa um mecanismo de "vitória em primeiro plano", que calcula a prioridade do aplicativo com base no status de primeiro ou segundo plano do aplicativo e no tipo de caso de uso. O TRM concede ou revoga o recurso com base na prioridade. TRM centraliza o gerenciamento de recursos ATV para transmissão, OTT e DVR.
Interface TRM
TRM expõe interfaces AIDL em ITunerResourceManager.aidl
para a estrutura Tuner, MediaCas
e TvInputHardwareManager
para registrar, solicitar ou liberar recursos.
As interfaces para gerenciamento de clientes estão listadas abaixo.
-
registerClientProfile(in ResourceClientProfile profile, IResourcesReclaimListener listener, out int[] clientId)
-
unregisterClientProfile(in int clientId)
As interfaces para solicitar e liberar recursos estão listadas abaixo.
-
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
As classes de cliente e solicitação estão listadas abaixo.
-
ResourceClientProfile
-
ResourcesReclaimListener
-
TunerFrontendRequest
-
TunerDemuxRequest
-
TunerDescramblerRequest
-
CasSessionRequest
-
TunerLnbRequest
Prioridade do cliente
O TRM calcula a prioridade do cliente usando parâmetros do perfil do cliente e o valor de prioridade do arquivo de configuração. A prioridade também pode ser atualizada por um valor de prioridade arbitrário do cliente.
Parâmetros no perfil do cliente
O TRM recupera o ID do processo de mTvInputSessionId
para decidir se um aplicativo é de primeiro ou segundo plano. Para criar mTvInputSessionId
, TvInputService.onCreateSession
ou TvInputService.onCreateRecordingSession
inicializa uma sessão TIS.
mUseCase
indica o caso de uso da sessão. Os casos de uso predefinidos estão listados abaixo.
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
}
Arquivo de configuração
Arquivo de configuração padrão
O arquivo de configuração padrão abaixo fornece valores de prioridade para casos de uso predefinidos. Os usuários podem alterar os valores usando um arquivo de configuração personalizado .
Caso de uso | Primeiro plano | Fundo |
---|---|---|
LIVE | 490 | 400 |
PLAYBACK | 480 | 300 |
RECORD | 600 | 500 |
SCAN | 450 | 200 |
BACKGROUND | 180 | 100 |
Arquivo de configuração personalizado
Os fornecedores podem personalizar o arquivo de configuração /vendor/etc/tunerResourceManagerUseCaseConfig.xml
. Este arquivo é usado para adicionar, remover ou atualizar os tipos de casos de uso e os valores de prioridade dos casos de uso. O arquivo customizado pode usar platform/hardware/interfaces/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml
como modelo.
Por exemplo, um novo caso de uso de fornecedor é VENDOR_USE_CASE__[A-Z0-9]+, [0 - 1000]
. O formato deve seguir platform/hardware/interfaces/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfig.xsd
.
Valor de prioridade arbitrário e valor agradável
TRM fornece updateClientPriority
para o cliente atualizar o valor de prioridade arbitrário e o valor agradável. O valor de prioridade arbitrário substitui o valor de prioridade calculado a partir do tipo de caso de uso e do ID da sessão.
O valor agradável indica quão tolerante é o comportamento do cliente quando está em conflito com outro cliente. O valor agradável diminui o valor de prioridade do cliente antes que seu valor de prioridade seja comparado ao cliente desafiador.
Mecanismo de recuperação
O diagrama abaixo mostra como os recursos são recuperados e atribuídos quando ocorre um conflito de recursos.
Figura 15. Diagrama do mecanismo de recuperação para um conflito entre recursos do Tuner