No Android 11 ou versões mais recentes, você pode usar o framework Tuner do Android para entregar conteúdo A/V. O framework usa o pipeline de hardware dos fornecedores, o que o torna adequado para SoCs de baixo e alto desempenho. O framework oferece 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 sintonizador e o CAS do Android resulta em uma integração mais rápida
entre os fornecedores de sintonizador e CAS. A interface do sintonizador funciona
com MediaCodec
e AudioTrack
para criar uma solução global para Android TV.
A interface do sintonizador oferece suporte a TV digital e analógica com base nos principais
padrões de transmissão.
Componentes
No Android 11, três componentes são 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 os recursos de sintonizador de hardware.
No Android 11, os seguintes componentes foram aprimorados.
- CAS V2
TvInputService
ou serviço de entrada de TV (TIS)TvInputManagerService
ou serviço de gerenciamento de entrada de TV (TIMS, na sigla em inglês)MediaCodec
ou codec de mídiaAudioTrack
ou faixa de áudioMediaResourceManager
ou media resource manager (MRM)
Figura 1. Interações entre componentes do Android TV
Recursos
O front-end oferece suporte aos padrões de 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 mais recente oferece suporte ao padrão DTV abaixo.
- DTMB
O Demux oferece suporte aos protocolos de transmissão abaixo.
- Stream de transporte (TS, na sigla em inglês)
- Protocolo de transporte de mídia MPEG (MMTP)
- Protocolo de Internet (IP)
- Valor de tipo e comprimento (TLV)
- Protocolo de camada de enlace ATSC (ALP)
O decodificador 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 Tuner oferecem suporte aos casos de uso abaixo.
- Verificar
- Live
- Reprodução
- Gravar
O Tuner, MediaCodec
e AudioTrack
oferecem suporte aos modos de fluxo de dados abaixo.
- Payload do ES com buffer de memória clara
- Payload ES com identificador de memória segura
- Transparente
Design em geral
O HAL do sintonizador é definido entre o framework do Android e o hardware do fornecedor.
- Descreve o que o framework espera do fornecedor e como ele pode fazer isso.
- Exporta as funcionalidades do front-end, demux e descrambler para o
framework usando as interfaces
IFrontend
,IDemux
,IDescrambler
,IFilter
,IDvr
eILnb
. - Inclui as funções para integrar o Tuner HAL a outros componentes
do framework, como
MediaCodec
eAudioTrack
.
Uma classe Java e uma classe nativa do Tuner são criadas.
- A API Java Tuner permite que os apps acessem o Tuner HAL por meio de 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 o HAL do sintonizador.
- O módulo de sintonizador nativo é uma ponte entre a classe Java do sintonizador e o HAL do sintonizador.
Uma classe de TRM é criada.
- Gerencia recursos limitados do sintonizador, como front-end, 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 CAS de mídia e o HAL de CAS foram aprimorados com os recursos abaixo.
- Abre sessões do CAS para diferentes usos e algoritmos.
- Suporte a sistemas CAS dinâmicos, como a remoção e inserção de CICAM.
- Integra-se ao Tuner HAL fornecendo tokens de chave.
MediaCodec
e AudioTrack
foram aprimorados com os recursos abaixo.
- Usa a memória de áudio/vídeo segura como entrada de conteúdo.
- Configurado para fazer sincronização A/V de hardware na reprodução em túnel.
- Configuração de suporte para
ES_payload
e modo de passagem.
Figura 2. Diagrama dos componentes no HAL do sintonizador
Fluxo de trabalho geral
Os diagramas abaixo ilustram sequências de chamadas para a reprodução de transmissão ao vivo.
Configurar
Figura 3. Configurar a sequência para a reprodução da transmissão ao vivo
Manuseio de A/V
Figura 4. Como processar áudio e vídeo para a 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 áudio e vídeo para reprodução de transmissão ao vivo
API Tuner SDK
A API Tuner SDK processa as interações com o JNI do Tuner, o HAL do Tuner
e o TunerResourceManager
. O app TIS usa a API SDK Tuner para acessar recursos
e subcomponentes do sintonizador, como o filtro e o decodificador. Frontend e
demux são componentes internos.
Figura 7. Interações com a API do Tuner SDK
Versões
No Android 12, a API Tuner SDK oferece suporte ao novo recurso no Tuner HAL 1.1, que é um upgrade de versão compatível com versões anteriores do Tuner 1.0.
Use a API abaixo para verificar a versão do HAL em execução.
android.media.tv.tuner.TunerVersionChecker.getTunerVersion()
A versão mínima necessária do 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.tuner
android.media.tv.tuner.frontend
android.media.tv.tuner.filter
android.media.tv.tuner.dvr
Figura 8. Pacotes da API do Tuner SDK
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 sintonizador especificando os parâmetrosuseCase
esessionId
.tune()
: adquire um recurso de front-end e faz ajustes 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 decodificador.openLnb()
: adquire uma instância interna de LNB.openLnbByName()
: adquire uma instância externa de LNB.openTimeFilter()
: adquire uma instância de filtro de tempo.
O pacote Tuner oferece funcionalidades que não estão incluídas nos pacotes de filtro, DVR e front-end. As funcionalidades estão listadas abaixo.
cancelTuning
scan
/cancelScanning
getAvSyncHwId
getAvSyncTime
connectCiCam1
/disconnectCiCam
shareFrontendFromTuner
updateResourcePriority
setOnTuneEventListener
setResourceLostListener
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
O FrontendSettings
é derivado de diferentes padrões de DTV pelas classes abaixo.
AnalogFrontendSettings
Atsc3FrontendSettings
AtscFrontendSettings
DvbcFrontendSettings
DvbsFrontendSettings
DvbtFrontendSettings
Isdbs3FrontendSettings
IsdbsFrontendSettings
IsdbtFrontendSettings
No Android 12 com Tuner HAL 1.1 ou mais recente, o seguinte padrão de TV digital é aceito.
DtmbFrontendSettings
O FrontendCapabilities
é derivado de diferentes padrões de DTV pelas classes
abaixo.
AnalogFrontendCapabilities
Atsc3FrontendCapabilities
AtscFrontendCapabilities
DvbcFrontendCapabilities
DvbsFrontendCapabilities
DvbtFrontendCapabilities
Isdbs3FrontendCapabilities
IsdbsFrontendCapabilities
IsdbtFrontendCapabilities
No Android 12 com Tuner HAL 1.1 ou mais recente, o seguinte padrão de TV digital é aceito.
DtmbFrontendCapabilities
FrontendInfo
recupera as informações do front-end.
FrontendStatus
recupera o status atual do front-end.
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 as frequências possíveis e cria uma programação
de canais para que os usuários acessem. 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 sinal, como frequência,
padrão (por exemplo, T/T2, S/S2) e outras informações necessárias
(por exemplo, ID do PLD), o
Tuner.tune
é recomendado como a opção mais rápida.
Quando o usuário chama Tuner.tune
, as seguintes ações acontecem:
- O TIS preenche
FrontendSettings
com as informações necessárias usandoTuner.tune
. - O HAL informa mensagens
LOCKED
de ajuste 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 lista de frequências.
O TIS chama Tuner.tune
novamente até que todas as frequências sejam esgotadas.
Durante a sintonização, é possível 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 o uso de 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)
comFrontendSettings
preenchido com frequência.O HAL informa a verificação de mensagens
LOCKED
se o sinal estiver bloqueado. O HAL também pode relatar outras mensagens de verificação para fornecer mais informações 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 vai usar a próxima configuração disponível. Caso contrário, o 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 verificação foi concluída.O TIS vai para a próxima frequência disponível na lista de frequências.
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 a
verificação.
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, recomendamos o uso de Tuner.scan(BLIND_SCAN)
.
- O TIS usa
Tuner.scan(BLIND_SCAN)
. Uma frequência pode ser especificada emFrontendSettings
para a frequência de início, mas o TIS ignora outras configurações emFrontendSettings
. - O HAL informa uma mensagem de verificação
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 verificação. (FrontendSettings
é ignorado.) - O TIS repete as ações acima até que todas as configurações da frequência sejam
esgotadas. O HAL incrementa a frequência sem que o TIS precise fazer nada.
O HAL informa
PROGRESS
.
O TIS chama Tuner.scan(AUTO_SCAN)
novamente até que todas as frequências sejam esgotadas.
O 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 de TIS
Android.media.tv.tuner.filter
O pacote de filtro é uma coleção de operações de filtro com configuração, configurações, callbacks e eventos. O pacote inclui as operações abaixo. Consulte o código-fonte do Android para conferir a lista completa de operações.
configure()
start()
stop()
flush()
read()
Consulte o código-fonte do Android para conferir 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 que tipos de dados o filtro pode excluir.
SectionSettings
AvSettings
PesSettings
RecordSettings
DownloadSettings
FilterEvent
é derivado das classes abaixo para informar eventos de diferentes
tipos de dados.
SectionEvent
MediaEvent
PesEvent
TsRecordEvent
MmtpRecordEvent
TemiEvent
DownloadEvent
IpPayloadEvent
No Android 12 com Tuner HAL 1.1 ou mais recente, os seguintes eventos são compatíveis:
IpCidChangeEvent
RestartEvent
ScramblingStatusEvent
Eventos e formato de dados do filtro
Tipo de filtro | Flags | 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 a 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 na 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 a 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 na 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 a 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 na 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/A | Obrigatório:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Recomendado: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::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 do MQ do HAL para o buffer do cliente. |
ts filtrado 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 depois de receber DemuxFilterStatus::DATA_OVERFLOW . |
N/A |
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 de AudioTrack :for i=0; i<n; i++ |
Dados de ES ou ES parcial na memória ION. | |
TS.PCR IP.NTP ALP.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_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 a programação interna, faça
uma das seguintes ações:
|
Para dados de índice:são transportados no payload do evento. Para conteúdo gravado:o fluxo TS mixado foi preenchido na FMQ. |
TS.TEMI |
N/A | 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/A |
MMTP.MMTP |
N/A | Obrigatório:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Recomendado: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::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 do MQ do HAL para o buffer do cliente. |
mmtp filtrado com cabeçalho mmtp é preenchido no FMQ. |
MMTP.RECORD |
N/A | 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 a programação interna, faça uma das
seguintes ações:
|
Para dados de índice:são transportados no payload do evento. Para conteúdo gravado:stream gravado mixado preenchido na FMQ. Se a origem do filtro para gravação for TLV.TLV para
IP.IP com passagem, o fluxo gravado terá um
TLV e um cabeçalho IP. |
MMTP.DOWNLOAD |
N/A | 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 de IP. |
IP.IP_PAYLOAD |
N/A | 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 payload IP é preenchido no FMQ por outro pacote de payload IP. |
IP.IP TLV.TLV ALP.ALP |
isPassthrough: |
Opcional:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW |
A subfluxo de protocolo filtrado alimenta o próximo filtro na cadeia de filtros. | N/A |
isPassthrough: |
Obrigatório:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW Recomendado: DemuxFilterStatus::LOW_WATER DemuxFilterStatus::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 do MQ do HAL para o buffer do cliente. |
A subfluxo do protocolo filtrado com cabeçalho de protocolo é preenchida na FMQ. | |
IP.PAYLOAD_THROUGH TLV.PAYLOAD_THROUGH ALP.PAYLOAD_THROUGH |
N/A | Opcional:DemuxFilterStatus::DATA_READY DemuxFilterStatus::DATA_OVERFLOW |
O payload do protocolo filtrado alimenta o próximo filtro na cadeia de filtros. | N/A |
Exemplo de fluxo para usar o filtro para 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();
Processe
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 o MediaEvent do filtro
- Abra, configure e inicie os filtros de áudio/vídeo.
- Processe
MediaEvent
. - Receba
MediaEvent
. - Coloque o bloco linear na fila para
codec
. - Libere 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 informar o status de uma instância de DVR.
Exemplo de fluxo para iniciar uma gravação
Figura 12. Fluxo para iniciar uma gravação
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
RecordEvent
e extraia 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. } } } };
Inicializar
OnRecordStatusChangedListener
e armazenar 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
O Tuner HAL segue o HIDL e define a interface entre o framework e o hardware do fornecedor. Os fornecedores usam a interface para implementar o HAL do sintonizador, e o framework a usa para se comunicar com a implementação do HAL do sintonizador.
Módulos
Tuner HAL 1.0
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.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 (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 sintonizador
Vinculação do filtro
O HAL do sintonizador oferece suporte à vinculação de filtros, de modo que os filtros possam ser vinculados a outros filtros para várias camadas. Os filtros seguem as regras abaixo.
- Os filtros são vinculados como uma árvore, e o caminho de fechamento 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 é limpa 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 alternância entre dois apps exigia o mesmo hardware do sintonizador. O TV Input Framework (TIF) usava um mecanismo de "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 sintonizador, TVInput
e CAS
para apps. O TRM usa um mecanismo de "prioridade 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 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)
/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 de 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 app
está em primeiro ou segundo plano. Para criar mTvInputSessionId
,
TvInputService.onCreateSession
ou TvInputService.onCreateRecordingSession
inicializa uma sessão de 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 de caso de uso e os valores de prioridade.
O arquivo personalizado pode usar
platform/hardware/interfaces/tv/tuner/1.0/config/tunerResourceManagerUseCaseConfigSample.xml
como 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 arbitrário e valor agradável
O TRM fornece updateClientPriority
para que o cliente atualize o valor de prioridade
arbitrário e o valor ideal.
O valor de prioridade arbitrário substitui o valor de prioridade calculado
com base no tipo de caso de uso e no ID da sessão.
O valor nice indica o quão flexível é o comportamento do cliente quando ele está em conflito com outro cliente. O valor bom diminui o valor de prioridade do cliente antes que ele seja comparado ao cliente desafiador.
Mecanismo de recuperação
O diagrama abaixo mostra como os recursos são recuperados e atribuídos quando um conflito de recursos acontece.
Figura 15. Diagrama do mecanismo de recuperação para um conflito entre recursos do Tuner