No Android 11 ou versões mais recentes, você pode usar o framework Tuner do Android para oferecer conteúdo A/V. O framework usa o pipeline de hardware dos fornecedores, o que o torna adequado para SoCs de baixo e alto custo. Ele oferece uma maneira segura de entregar conteúdo de áudio/vídeo protegido por um ambiente de execução confiável (TEE) e um caminho de mídia seguro (SMP), permitindo que 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 de Tuner e CAS. A interface do Tuner funciona com MediaCodec e AudioTrack para criar uma solução global para o Android TV.
A interface Tuner é compatível com TV digital e analógica com base nos principais padrões de transmissão.
Componentes
No Android 11, três componentes foram projetados especificamente para a plataforma de TV.
- HAL do sintonizador:uma interface entre o framework e os fornecedores.
- API do SDK Tuner:uma interface entre o framework e os apps.
- Tuner Resource Manager (TRM): coordena recursos de hardware do sintonizador.
No Android 11, os seguintes componentes foram melhorados.
- CAS V2
TvInputServiceou serviço de entrada de TV (TIS, na sigla em inglês)TvInputManagerServiceou serviço de gerenciamento de entrada de TV (TIMS, na sigla em inglês)MediaCodecou codec de mídiaAudioTrackou faixa de áudioMediaResourceManagerou gerenciador de recursos de mídia (MRM, na sigla em inglês).
Figura 1. Interações entre componentes do Android TV
Recursos
O front-end é compatível com os padrões de DTV abaixo.
- ATSC
- ATSC3
- DVB C/S/T
- ISDB S/S3/T
- Analógico
O front-end no Android 12 com o Tuner HAL 1.1 ou versões mais recentes oferece suporte ao padrão DTV abaixo.
- DTMB
O Demux é compatível com os protocolos de stream abaixo.
- Stream de transporte (TS)
- Protocolo de transporte de mídia MPEG (MMTP)
- Protocolo de Internet (IP)
- Valor de comprimento do tipo (TLV)
- Protocolo de camada de link ATSC (ALP)
O descrambler é compatível com as proteções de conteúdo abaixo.
- Caminho de mídia seguro
- Limpar o caminho da mídia
- Proteger registro local
- Reprodução local segura
As APIs Tuner são compatíveis com os casos de uso abaixo.
- Verificar
- Live
- Reprodução
- Gravar
O Tuner, MediaCodec e AudioTrack são compatíveis com os modos de fluxo de dados abaixo.
- Payload do ES com buffer de memória limpo
- Payload do ES com identificador de memória seguro
- Transparente
Design em geral
O Tuner HAL é definido entre o framework do Android e o hardware do fornecedor.
- Descreve o que a estrutura espera do fornecedor e como ele pode fazer isso.
- Exporta as funcionalidades de front-end, demux e descrambler para o
framework pelas interfaces
IFrontend,IDemux,IDescrambler,IFilter,IDvreILnb. - Inclui as funções para integrar a HAL do Tuner com outros componentes
do framework, como
MediaCodeceAudioTrack.
Uma classe Java e uma classe nativa do Tuner são criadas.
- A API Tuner Java permite que os apps acessem o Tuner HAL por APIs públicas.
- A classe nativa permite o controle de permissões e o processamento de grandes quantidades de dados de gravação ou reprodução com a HAL do sintonizador.
- O módulo Native Tuner é uma ponte entre a classe Tuner Java e a HAL do Tuner.
Uma classe de TRM é criada.
- Gerencia recursos limitados do sintonizador, como frontend, LNB, sessões CAS e um dispositivo de entrada de TV do HAL de entrada de TV.
- Aplica regras para recuperar recursos insuficientes de apps. A regra padrão é a vitória em primeiro plano.
O Media CAS e o CAS HAL foram aprimorados com os recursos abaixo.
- Abre sessões do CAS para diferentes usos e algoritmos.
- Compatível com sistemas CAS dinâmicos, como remoção e inserção de CICAM.
- Integra-se à HAL do sintonizador fornecendo tokens de chave.
MediaCodec e AudioTrack foram aprimorados com os recursos abaixo.
- Usa memória A/V segura como entrada de conteúdo.
- Configurado para fazer sincronização de A/V de hardware na reprodução em túnel.
- Configuramos o suporte para
ES_payloade o modo de transferência.
Figura 2. Diagrama dos componentes no HAL do Tuner
Fluxo de trabalho geral
Os diagramas abaixo ilustram sequências de chamadas para reprodução de transmissões ao vivo.
Configuração
Figura 3. Sequência de configuração para reprodução de transmissão ao vivo
Manuseio de A/V
Figura 4. Como processar A/V para reprodução de transmissões ao vivo
Como lidar com conteúdo codificado
Figura 5. Como lidar com conteúdo codificado para reprodução de transmissões ao vivo
Processamento de dados de áudio/vídeo
Figura 6. Processamento de A/V para reprodução de transmissão ao vivo
API Tuner SDK
A API Tuner SDK processa as interações com o Tuner JNI, o Tuner HAL
e TunerResourceManager. O app TIS usa a API Tuner SDK para acessar recursos e subcomponentes do Tuner, como o filtro e o descrambler. O front-end e o demux são componentes internos.
Figura 7. Interações com a API do SDK Tuner
Versões
A partir do Android 12, a API Tuner SDK oferece suporte a um novo recurso no Tuner HAL 1.1, que é um upgrade do Tuner 1.0 compatível com versões anteriores.
Use a API a seguir para verificar a versão do HAL em execução.
android.media.tv.tuner.TunerVersionChecker.getTunerVersion()
A versão mínima necessária da HAL pode ser encontrada na documentação das novas APIs do Android 12.
Pacotes
A API Tuner SDK oferece os quatro pacotes abaixo.
android.media.tv.tunerandroid.media.tv.tuner.frontendandroid.media.tv.tuner.filterandroid.media.tv.tuner.dvr
Figura 8. Pacotes da API do SDK Tuner
Android.media.tv.tuner
O pacote Tuner é um ponto de entrada para usar o framework Tuner. O app TIS usa o pacote para inicializar e adquirir instâncias de recursos especificando a configuração inicial e o callback.
tuner(): inicializa uma instância do Tuner especificando os parâmetrosuseCaseesessionId.tune(): adquire um recurso de front-end 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 de descrambler.openLnb(): adquire uma instância interna do LNB.openLnbByName(): adquire uma instância de LNB externa.openTimeFilter(): adquire uma instância de filtro de tempo.
O pacote Tuner oferece funcionalidades que não são cobertas pelos pacotes de filtro, DVR e front-end. As funcionalidades estão listadas abaixo.
cancelTuningscan/cancelScanninggetAvSyncHwIdgetAvSyncTimeconnectCiCam1/disconnectCiCamshareFrontendFromTunerupdateResourcePrioritysetOnTuneEventListenersetResourceLostListener
Android.media.tv.tuner.frontend
O pacote de front-end inclui coleções de configurações, informações, status, eventos e recursos relacionados ao front-end.
Classes
FrontendSettings é derivado para diferentes padrões de DTV pelas classes abaixo.
AnalogFrontendSettingsAtsc3FrontendSettingsAtscFrontendSettingsDvbcFrontendSettingsDvbsFrontendSettingsDvbtFrontendSettingsIsdbs3FrontendSettingsIsdbsFrontendSettingsIsdbtFrontendSettings
No Android 12 com o Tuner HAL 1.1 ou versões mais recentes, o seguinte padrão de DTV é compatível.
DtmbFrontendSettings
FrontendCapabilities é derivado para diferentes padrões de DTV pelas classes abaixo.
AnalogFrontendCapabilitiesAtsc3FrontendCapabilitiesAtscFrontendCapabilitiesDvbcFrontendCapabilitiesDvbsFrontendCapabilitiesDvbtFrontendCapabilitiesIsdbs3FrontendCapabilitiesIsdbsFrontendCapabilitiesIsdbtFrontendCapabilities
No Android 12 com o Tuner HAL 1.1 ou versões mais recentes, o seguinte padrão de DTV é compatível.
DtmbFrontendCapabilities
O FrontendInfo recupera as informações do front-end.
O FrontendStatus recupera o status atual do front-end.
O OnTuneEventListener detecta os eventos no front-end.
O app TIS usa ScanCallback para processar mensagens de verificação do front-end.
Busca de canais
Para configurar uma TV, o app verifica possíveis frequências e cria uma lista 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 verificação do canal.
Se o TIS tiver informações de entrega precisas para o indicador, como frequência, padrão (por exemplo, T/T2, S/S2) e outras informações necessárias (por exemplo, ID do PLD), recomendamos Tuner.tune como a opção mais rápida.
Quando o usuário chama Tuner.tune, as seguintes ações acontecem:
- O TIS preenche
FrontendSettingscom as informações necessárias usandoTuner.tune. - A HAL informa mensagens de ajuste
LOCKEDse o sinal estiver bloqueado. - O TIS usa o
Frontend.getStatuspara coletar as informações necessárias. - O TIS passa para a próxima frequência disponível na lista.
O TIS chama Tuner.tune novamente até que todas as frequências sejam esgotadas.
Durante o ajuste, 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), recomendamos usar Tuner.scan(AUTO_SCAN).
Quando o usuário chama Tuner.scan(AUTO_SCAN), as seguintes ações acontecem:
O TIS usa
Tuner.scan(AUTO_SCAN)comFrontendSettingspreenchido com frequência.A HAL informa mensagens de verificação
LOCKEDse o indicador estiver bloqueado. A HAL também pode informar outras mensagens de verificação para fornecer mais informações sobre o sinal.O TIS usa o
Frontend.getStatuspara coletar as informações necessárias.O TIS chama
Tuner.scanpara que a HAL continue com a próxima configuração na mesma frequência. Se a estruturaFrontendSettingsestiver vazia, a HAL usará a próxima configuração disponível. Caso contrário, a HAL usaFrontendSettingspara uma verificação única e enviaENDpara indicar que a operação de verificação foi concluída.O TIS repete as ações acima até que todas as configurações na frequência sejam esgotadas.
A HAL envia
ENDpara indicar que a operação de verificação foi concluída.O TIS passa para a próxima frequência disponível na lista.
O TIS chama Tuner.scan(AUTO_SCAN) novamente até que todas as frequências sejam esgotadas.
Durante a verificação, você pode chamar stopScan() ou close() para pausar ou encerrar o processo.
Tuner.scan(BLIND_SCAN)
Se o TIS não tiver uma lista de frequências e o HAL do fornecedor puder pesquisar a frequência do front-end especificado pelo usuário para receber o recurso de front-end, Tuner.scan(BLIND_SCAN) será recomendado.
- O TIS usa
Tuner.scan(BLIND_SCAN). Uma frequência pode ser especificada emFrontendSettingspara frequência de início, mas o TIS ignora outras configurações emFrontendSettings. - A HAL informa uma mensagem de busca
LOCKEDse o sinal estiver bloqueado. - O TIS usa o
Frontend.getStatuspara coletar as informações necessárias. - O TIS chama
Tuner.scannovamente para continuar a verificação. (FrontendSettingsé ignorado.) - O TIS repete as ações acima até que todas as configurações na frequência sejam esgotadas. A HAL aumenta a frequência sem que o TIS precise fazer nada.
A HAL informa
PROGRESS.
O TIS chama Tuner.scan(AUTO_SCAN) novamente até que todas as frequências sejam esgotadas.
A HAL informa END para indicar que a operação de verificação foi concluída.
Durante a verificação, você pode chamar stopScan() ou close() para pausar ou encerrar a verificação.
Figura 9. Diagrama de fluxo de uma verificação do TIS
Android.media.tv.tuner.filter
O pacote de filtros é uma coleção de operações de filtragem com configuração, configurações, callbacks e eventos. O pacote inclui as operações abaixo. Consulte o código-fonte do Android para ver a lista completa de operações.
configure()start()stop()flush()read()
Consulte o código-fonte do Android para ver 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.
AlpFilterConfigurationIpFilterConfigurationMmtpFilterConfigurationTlvFilterConfigurationTsFilterConfiguration
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 ele pode excluir.
SectionSettingsAvSettingsPesSettingsRecordSettingsDownloadSettings
FilterEvent é derivado das classes abaixo para informar eventos de diferentes tipos de dados.
SectionEventMediaEventPesEventTsRecordEventMmtpRecordEventTemiEventDownloadEventIpPayloadEvent
No Android 12 com o Tuner HAL 1.1 ou versões mais recentes, os seguintes eventos são compatíveis.
IpCidChangeEventRestartEventScramblingStatusEvent
Eventos e formato de dados do filtro
| Tipo de filtro | Flags | Eventos | Operação de dados | Formato de dados |
|---|---|---|---|---|
TS.SECTIONMMTP.SECTIONIP.SECTIONTLV.SECTIONALP.SECTION |
isRaw: |
Obrigatório:DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOWRecomendado: DemuxFilterStatus::LOW_WATERDemuxFilterStatus::HIGH_WATER |
De acordo com o evento e a programação interna, executeFilter.read(buffer, offset, adjustedSize) uma ou mais
vezes.Os dados são copiados da MQ da HAL para o buffer do cliente. |
Um pacote de sessão montado é preenchido na FMQ por outro pacote de sessão. |
isRaw: |
Obrigatório:DemuxFilterEvent::DemuxFilterSectionEvent[n]DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOWOpcional: DemuxFilterStatus::LOW_WATERDemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i++Os dados são copiados da MQ da HAL para o buffer do cliente. |
||
TS.PES |
isRaw: |
Obrigatório:DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOWRecomendado: DemuxFilterStatus::LOW_WATERDemuxFilterStatus::HIGH_WATER |
De acordo com o evento e a programação interna, executeFilter.read(buffer, offset, adjustedSize) uma ou mais
vezes.Os dados são copiados da fila de mensagens da HAL para o buffer do cliente. |
Um pacote PES montado é preenchido em FMQ por outro pacote PES. |
isRaw: |
Obrigatório:DemuxFilterEvent::DemuxFilterPesEvent[n]DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOWOpcional: DemuxFilterStatus::LOW_WATERDemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i++Os dados são copiados da MQ da HAL para o buffer do cliente. |
||
MMTP.PES |
isRaw: |
Obrigatório:DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOWRecomendado: DemuxFilterStatus::LOW_WATERDemuxFilterStatus::HIGH_WATER |
De acordo com o evento e a programação interna, executeFilter.read(buffer, offset, adjustedSize) uma ou mais
vezes.Os dados são copiados da MQ da HAL para o buffer do cliente. |
Um pacote MFU montado é preenchido na FMQ por outro pacote MFU. |
isRaw: |
Obrigatório:DemuxFilterEvent::DemuxFilterPesEvent[n]DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOWOpcional: DemuxFilterStatus::LOW_WATERDemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i++Os dados são copiados da MQ da HAL para o buffer do cliente. |
||
TS.TS |
N/A | Obrigatório:DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOWRecomendado: DemuxFilterStatus::LOW_WATERDemuxFilterStatus::HIGH_WATER |
De acordo com o evento e a programação interna, executeFilter.read(buffer, offset, adjustedSize) uma ou mais
vezes.Os dados são copiados da MQ da HAL para o buffer do cliente. |
ts filtrado com cabeçalho tspreenchido na FMQ. |
TS.AudioTS.VideoMMTP.AudioMMTP.Video |
isPassthrough: |
Opcional:DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOW |
O cliente pode iniciar MediaCodec depois de receber DemuxFilterStatus::DATA_READY.O cliente pode chamar Filter.flush depois de receber DemuxFilterStatus::DATA_OVERFLOW. |
N/A |
isPassthrough: |
Obrigatório:DemuxFilterEvent::DemuxFilterMediaEvent[n]DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOWOpcional: DemuxFilterStatus::LOW_WATERDemuxFilterStatus::HIGH_WATER |
Para usar o MediaCodec:for i=0; i<n; i++Para usar o áudio direto do AudioTrack:for i=0; i<n; i++ |
Dados de ES ou ES parcial na memória ION. | |
TS.PCRIP.NTPALP.PTP |
N/A | Obrigatório:N/A
Opcional:N/A |
N/A | N/A |
TS.RECORD |
N/A | Obrigatório: DemuxFilterEvent::DemuxFilterTsRecordEvent[n]RecordStatus::DATA_READYRecordStatus::DATA_OVERFLOWRecordStatus::LOW_WATERRecordStatus::HIGH_WATEROpcional: DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOWDemuxFilterStatus::LOW_WATERDemuxFilterStatus::HIGH_WATER |
Para dados de índice:for i=0; i<n; i++Para conteúdo gravado, de acordo com RecordStatus::* e a programação interna, faça
uma das seguintes ações:
|
Para dados de índice:incluídos no payload do evento. Para conteúdo gravado:fluxo TS muxado preenchido na FMQ. |
TS.TEMI |
N/A | Obrigatório:DemuxFilterEvent::DemuxFilterTemiEvent[n]Opcional: DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOWDemuxFilterStatus::LOW_WATERDemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i++ |
N/A |
MMTP.MMTP |
N/A | Obrigatório:DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOWRecomendado: DemuxFilterStatus::LOW_WATERDemuxFilterStatus::HIGH_WATER |
De acordo com o evento e a programação interna, executeFilter.read(buffer, offset, adjustedSize) uma ou mais
vezes.Os dados são copiados da MQ da HAL para o buffer do cliente. |
mmtp filtrado com cabeçalho mmtppreenchido na FMQ. |
MMTP.RECORD |
N/A | Obrigatório:DemuxFilterEvent::DemuxFilterMmtpRecordEvent[n]RecordStatus::DATA_READYRecordStatus::DATA_OVERFLOWRecordStatus::LOW_WATERRecordStatus::HIGH_WATEROpcional: DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOWDemuxFilterStatus::LOW_WATERDemuxFilterStatus::HIGH_WATER |
Para dados de índice: for i=0; i<n; i++Para conteúdo gravado, de acordo com RecordStatus::* e programação interna, faça uma das
seguintes ações:
|
Para dados de índice:incluídos no payload do evento. Para conteúdo gravado:stream gravado muxado preenchido FMQ. Se a origem do filtro para gravação for TLV.TLV para
IP.IP com transmissão direta, o stream gravado terá um
cabeçalho TLV e IP. |
MMTP.DOWNLOAD |
N/A | Obrigatório:DemuxFilterEvent::DemuxFilterDownloadEvent[n]DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOWOpcional: DemuxFilterStatus::LOW_WATERDemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i++
Filter.read(buffer, offset, DemuxFilterDownloadEvent[i].size)Os dados são copiados da MQ da HAL para o buffer do cliente. |
O pacote de download é preenchido na FMQ por outro pacote de download de IP. |
IP.IP_PAYLOAD |
N/A | Obrigatório:DemuxFilterEvent::DemuxFilterIpPayloadEvent[n]DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOWOpcional: DemuxFilterStatus::LOW_WATERDemuxFilterStatus::HIGH_WATER |
for i=0; i<n; i++
Filter.read(buffer, offset, DemuxFilterIpPayloadEvent[i].size)Os dados são copiados da MQ da HAL para o buffer do cliente. |
O pacote de payload IP é preenchido na FMQ por outro pacote de payload IP. |
IP.IPTLV.TLVALP.ALP |
isPassthrough: |
Opcional:DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOW |
O fluxo secundário de protocolo filtrado alimenta o próximo filtro na cadeia de filtros. | N/A |
isPassthrough: |
Obrigatório:DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOWRecomendado: DemuxFilterStatus::LOW_WATERDemuxFilterStatus::HIGH_WATER |
De acordo com o evento e a programação interna, executeFilter.read(buffer, offset, adjustedSize) uma ou mais
vezes.Os dados são copiados da MQ da HAL para o buffer do cliente. |
Subfluxo de protocolo filtrado com cabeçalho de protocolo preenchido FMQ. | |
IP.PAYLOAD_THROUGHTLV.PAYLOAD_THROUGHALP.PAYLOAD_THROUGH |
N/A | Opcional:DemuxFilterStatus::DATA_READYDemuxFilterStatus::DATA_OVERFLOW |
O payload de protocolo filtrado alimenta o próximo filtro na cadeia de filtros. | N/A |
Fluxo de exemplo para usar o filtro e criar PSI/SI
Figura 10. Fluxo para criar 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); } } } };
Exemplo de fluxo para usar MediaEvent do filtro
Figura 11. Fluxo para usar MediaEvent do filtro
- Abra, configure e inicie os filtros de áudio e vídeo.
- Processar
MediaEvent. - Receber
MediaEvent. - Coloque o bloco linear na fila para
codec. - Libere o identificador de A/V quando os dados forem consumidos.
Android.media.tv.tuner.dvr
O DvrRecorder fornece estes métodos para gravação.
configureattachFilterdetachFilterstartflushstopsetFileDescriptorwrite
O DvrPlayback oferece esses métodos para reprodução.
configurestartflushstopsetFileDescriptorread
DvrSettings é usado para configurar DvrRecorder e DvrPlayback.
OnPlaybackStatusChangedListener e OnRecordStatusChangedListener são usados para informar o status de uma instância de DVR.
Exemplo de fluxo para iniciar um registro
Figura 12. Fluxo para iniciar um registro
Abra, configure e inicie o
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
RecordEvente 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
OnRecordStatusChangedListenere 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); } } };
HAL do sintonizador
A HAL do sintonizador segue o HIDL e define a interface entre o framework e o hardware do fornecedor. Os fornecedores usam a interface para implementar a HAL do Tuner, e o framework a usa para se comunicar com a implementação da HAL do Tuner.
Módulos
HAL 1.0 do sintonizador
| Módulos | Controles básicos | Controles específicos do módulo | Arquivos HAL |
|---|---|---|---|
ITuner |
N/A | frontend(open, getIds, getInfo), openDemux,
openDescrambler, openLnb,
getDemuxCaps |
ITuner.hal |
IFrontend |
setCallback, getStatus, close
| tune, stopTune, scan,
stopScan, setLnb |
IFrontend.halIFrontendCallback.hal |
IDemux |
close |
setFrontendDataSource, openFilter, openDvr, getAvSyncHwId,
getAvSyncTime, connect / disconnectCiCam |
IDemux.hal |
IDvr |
close, start, stop, configure |
attach/detachFilters, flush, getQueueDesc |
IDvr.halIDvrCallback.hal |
IFilter |
close, start, stop, configure, getId |
flush, getQueueDesc, releaseAvHandle, setDataSource |
IFilter.halIFilterCallback.hal |
ILnb |
close, setCallback |
setVoltage, setTone, setSatellitePosition, sendDiseqcMessage |
ILnb.halILnbCallback.hal |
IDescrambler |
close |
setDemuxSource, setKeyToken,
addPid, removePid |
IDescrambler.hal |
Tuner HAL 1.1 (derivado do Tuner HAL 1.0)
| Módulos | Controles básicos | Controles específicos do módulo | Arquivos HAL |
|---|---|---|---|
ITuner |
N/A | 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 HAL do Tuner
Vinculação de filtros
O Tuner HAL oferece suporte à vinculação de filtros para que eles possam ser vinculados a outros filtros em várias camadas. Os filtros seguem as regras abaixo.
- Os filtros são vinculados como uma árvore, e o caminho fechado não é permitido.
- O nó raiz é demux.
- Os filtros funcionam de forma independente.
- Todos os filtros começam a receber dados.
- A vinculação de filtro é liberada no último filtro.
O bloco de código abaixo e a Figura 14 ilustram um exemplo de filtragem de várias 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 vinculação de filtro para várias camadas
Tuner Resource Manager
Antes do Tuner Resource Manager (TRM), a troca entre dois apps exigia o mesmo hardware de sintonizador. O TV Input Framework (TIF) usava um mecanismo de "ganho do primeiro a adquirir", o que significa que o app que recebe o recurso primeiro o mantém. No entanto, esse mecanismo pode não ser ideal para alguns casos de uso complicados.
O TRM é executado como um serviço do sistema para gerenciar os recursos de hardware do Tuner, TVInput e CAS
para apps. A TRM usa um mecanismo de "vitória em primeiro plano", que calcula a prioridade do app com base no status em primeiro ou segundo plano e no tipo de caso de uso. O TRM concede ou revoga o recurso com base na prioridade. O TRM centraliza o gerenciamento de recursos de ATV para transmissão, OTT e DVR.
Interface do TRM
O TRM expõe interfaces AIDL em ITunerResourceManager.aidl para o framework
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)/releaseFrontendrequestDemux(TunerDemuxRequest request, int[] demuxHandle)/releaseDemuxrequestDescrambler(TunerDescramblerRequest request, int[] descramblerHandle)/releaseDescramblerrequestCasSession(CasSessionRequest request, int[] casSessionHandle)/releaseCasSessionrequestLnb(TunerLnbRequest request, int[] lnbHandle)/releaseLnb
As classes de cliente e de solicitação estão listadas abaixo.
ResourceClientProfileResourcesReclaimListenerTunerFrontendRequestTunerDemuxRequestTunerDescramblerRequestCasSessionRequestTunerLnbRequest
Prioridade do cliente
A TRM calcula a prioridade do cliente usando parâmetros do perfil dele e o valor de prioridade do arquivo de configuração. A prioridade também pode ser atualizada por um valor arbitrário do cliente.
Parâmetros no perfil do cliente
A TRM recupera o ID do processo de mTvInputSessionId para decidir se um app está em primeiro ou segundo plano. Para criar mTvInputSessionId, TvInputService.onCreateSession ou TvInputService.onCreateRecordingSession, inicialize uma sessão do TIS.
mUseCase indica o caso de uso da sessão. Confira abaixo os casos de uso predefinidos.
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 mudar os valores usando um arquivo de configuração personalizado.
| Caso de uso | Primeiro plano | Contexto |
|---|---|---|
LIVE |
490 | 400 |
PLAYBACK |
sobreposição ou | 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. Esse arquivo é usado para adicionar, remover ou atualizar os tipos e valores de prioridade de caso de uso.
O arquivo personalizado pode usar
platform/hardware/interfaces/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml
como um modelo.
Por exemplo, um novo caso de uso do fornecedor é VENDOR_USE_CASE__[A-Z0-9]+, [0 - 1000].
O formato precisa seguir
platform/hardware/interfaces/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfig.xsd.
Valor de prioridade e valor nice arbitrários
A TRM fornece updateClientPriority para o cliente atualizar o valor de prioridade e o valor nice arbitrários.
O valor de prioridade arbitrário substitui o valor calculado com base no tipo de caso de uso e no ID da sessão.
O valor nice indica o nível de tolerância do comportamento do cliente quando ele está em conflito com outro cliente. O valor nice diminui a prioridade do cliente antes que ela seja comparada à do 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