Framework Tuner

No Android 11 ou versões mais recentes, você pode usar o framework do Android Tuner para fornecer 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 Tuner e o Android CAS resulta em uma integração mais rápida entre os fornecedores do Tuner e os fornecedores de CAS. A interface do sintonizador funciona com MediaCodec e AudioTrack para criar uma solução global para Android TV. A interface do Tuner oferece suporte à 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.

  • Tuner HAL:é uma interface entre o framework e os fornecedores.
  • API Tuner SDK: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 o TV Input Manager Service (TIMS)
  • MediaCodec ou codec de mídia
  • AudioTrack ou faixa de áudio
  • MediaResourceManager ou media resource manager (MRM)

Diagrama de fluxo dos componentes do framework Tuner.

Figura 1. Interações entre componentes do Android TV

Recursos

O front-end é compatível com 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 mais recente 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 tipo e comprimento (TLV, na sigla em inglês)
  • Protocolo de camada de link (ALP, na sigla em inglês) ATSC

O decodificador oferece suporte às proteções de conteúdo abaixo.

  • Caminho de mídia seguro
  • Limpar caminho de mídia
  • Proteger registro local
  • Reprodução local segura

As APIs Tuner oferecem suporte aos casos de uso abaixo.

  • Verificar
  • Ao vivo
  • 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 clara
  • Payload ES com gerenciador de memória seguro
  • Transparente

Design em geral

A HAL do Tuner é definida 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 e ILnb.
  • Inclui as funções para integrar o Tuner HAL a outros componentes do framework, como MediaCodec e AudioTrack.

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 a HAL Tuner.
  • O módulo de sintonizador nativo é uma ponte entre a classe Java do sintonizador e o HAL do sintonizador.

Uma classe 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 com a HAL de sintonizador fornecendo tokens de chave.

MediaCodec e AudioTrack foram aprimorados com os recursos abaixo.

  • Usa a memória A/V segura como entrada de conteúdo.
  • Configurado para fazer a sincronização A/V de hardware na reprodução em túnel.
  • Configuração de suporte para ES_payload e modo de passagem.

Design geral do HAL do sintonizador.

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

Diagrama de sequência de configuração da reprodução de transmissão ao vivo.

Figura 3. Sequência de configurações para reprodução de transmissão ao vivo

Manuseio de A/V

Como processar A/V para diagrama de reprodução de transmissão ao vivo.

Figura 4. Como processar áudio e vídeo para a reprodução de transmissões ao vivo

Como processar conteúdo embaralhado

Diagrama de processamento de conteúdo embaralhado de transmissão ao vivo.

Figura 5. Como processar conteúdo embaralhado para reprodução de transmissão ao vivo

Como processar dados A/V

Processar dados de áudio/vídeo para o diagrama de reprodução de transmissão ao vivo.

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. Front-end e demux são componentes internos.

Diagrama de fluxo da API Tuner SDK.

Figura 7. Interações com a API Tuner SDK

Versões

No Android 12 e versões mais recentes, a API Tuner SDK oferece suporte ao novo recurso do 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 da 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

Diagrama de fluxo dos pacotes da API do Tuner SDK.

Figura 8. Pacotes da API 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âmetros useCase e sessionId.
  • tune(): adquire um recurso de front-end e faz ajustes especificando o parâmetro FrontendSetting.
  • openFilter(): recebe 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 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 para 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 DTV é aceito.

  • DtmbFrontendSettings

A FrontendCapabilities é derivada para diferentes padrões de DTV pelas classes abaixo.

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

No Android 12 com o Tuner HAL 1.1 ou mais recente, o padrão DTV abaixo tem suporte.

  • DtmbFrontendCapabilities

FrontendInfo recupera as informações do front-end. 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 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 de canais.

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 usando Tuner.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ência.

O TIS chama Tuner.tune de novo até que todas as frequências sejam esgotadas.

Durante o ajuste, é 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) com FrontendSettings preenchidos com frequência.

  • O HAL informa a detecçã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 estrutura FrontendSettings estiver vazia, a HAL usará a próxima configuração disponível. Caso contrário, o HAL usa FrontendSettings para uma verificação única e envia END 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.

  • A HAL envia END para indicar que a operação de verificação foi concluída.

  • O TIS passa para a próxima frequência disponível na lista de frequência.

O TIS chama Tuner.scan(AUTO_SCAN) novamente até que todas as frequências sejam esgotadas.

Durante a verificação, é possível chamar stopScan() ou close() para pausar ou finalizar a verificação.

Tuner.scan(BLIND_SCAN)

Se o TIS não tiver uma lista de frequência e a HAL do fornecedor puder pesquisar a frequência do front-end especificado pelo usuário para receber o recurso de front-end, recomendamos Tuner.scan(BLIND_SCAN).

  • O TIS usa Tuner.scan(BLIND_SCAN). Uma frequência pode ser especificada em FrontendSettings para a frequência de início, mas o TIS ignora outras configurações em FrontendSettings.
  • 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. A HAL incrementa a frequência sem necessidade de ação da TIS. A HAL informa PROGRESS.

O TIS chama Tuner.scan(AUTO_SCAN) de novo 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 leitura, é possível chamar stopScan() ou close() para pausar ou finalizar a verificação.

Diagrama de fluxo do processo de verificação de TIS.

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, além de 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

O FilterEvent é derivado das classes abaixo para relatar eventos para diferentes tipos de dados.

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

No Android 12 com o Tuner HAL 1.1 ou mais recente, os eventos abaixo têm suporte.

  • 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:
true
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, execute
Filter.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:
false
Obrigatório:
DemuxFilterEvent::DemuxFilterSectionEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

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


Os dados são copiados do MQ do HAL para o buffer do cliente.
TS.PES isRaw:
true
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, execute
Filter.read(buffer, offset, adjustedSize) uma ou mais vezes.

Os dados são copiados do MQ da HAL para o buffer do cliente.
Um pacote PES montado é preenchido na FMQ por outro pacote PES.
isRaw:
false
Obrigatório:
DemuxFilterEvent::DemuxFilterPesEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

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


Os dados são copiados do MQ do HAL para o buffer do cliente.
MMTP.PES isRaw:
true
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, execute
Filter.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 em FMQ por outro pacote MFU.
isRaw:
false
Obrigatório:
DemuxFilterEvent::DemuxFilterPesEvent[n]
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW

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


Os dados são copiados do MQ da 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, execute
Filter.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:
true
Opcional:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::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:
false
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++
linearblock = MediaEvent[i].getLinearBlock();
codec.startQueueLinearBlock(linearblock)
linearblock.recycle()


Para usar o áudio direto de AudioTrack:
for i=0; i<n; i++
audioHandle = MediaEvent[i].getAudioHandle();
audiotrack.write(encapsulated(audiohandle))
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++
DemuxFilterTsRecordEvent[i];


Para conteúdo gravado, de acordo com RecordStatus::* e a programação interna, siga um destes procedimentos:
  • Execute DvrRecord.write(adustedSize) uma ou mais vezes para armazenar.
    Os dados são transferidos do MQ da HAL para o armazenamento.
  • Execute DvrRecord.write(buffer, adustedSize) uma ou mais vezes para armazenar em buffer.
    Os dados são copiados do MQ da HAL para o buffer do cliente.
Para dados de índice: 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++
DemuxFilterTemiEvent[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, execute
Filter.read(buffer, offset, adjustedSize) uma ou mais vezes.

Os dados são copiados do MQ da HAL para o buffer do cliente.
O 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++
DemuxFilterMmtpRecordEvent[i];


Para conteúdo gravado, de acordo com RecordStatus::* e a programação interna, faça uma das seguintes ações:
  • Execute DvrRecord.write(adjustedSize) uma ou mais vezes para o armazenamento.
    Os dados são transferidos do MQ da HAL para o armazenamento.
  • Execute DvrRecord.write(buffer, adjustedSize)uma ou mais vezes para armazenar em buffer.
    Os dados são copiados do MQ da HAL para o buffer do cliente.
Para dados de índice: são transportados no payload do evento.

Para conteúdo gravado: stream gravado com multiplexação preenchida em 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 da 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:
true
Opcional:
DemuxFilterStatus::DATA_READY
DemuxFilterStatus::DATA_OVERFLOW
A subfluxo de protocolo filtrado alimenta o próximo filtro na cadeia de filtros. N/A
isPassthrough:
false
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, execute
Filter.read(buffer, offset, adjustedSize) uma ou mais vezes.

Os dados são copiados do MQ da HAL para o buffer do cliente.
O subfluxo do protocolo filtrado com o cabeçalho do protocolo é preenchido em 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

Exemplo de fluxo de uso do filtro para criar PSI/SI.

Figura 10. Fluxo para criar PSI/SI

  1. Abra um filtro.

    Filter filter = tuner.openFilter(
      Filter.TYPE_TS,
      Filter.SUBTYPE_SECTION,
      /* bufferSize */1000,
      executor,
      filterCallback
    );
    
  2. 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();
    
  3. 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

Exemplo de fluxo para usar o MediaEvent do filtro.

Figura 11. Fluxo para usar o MediaEvent do filtro

  1. Abra, configure e inicie os filtros de áudio/vídeo.
  2. Processar MediaEvent.
  3. Receba MediaEvent.
  4. Coloque o bloco linear na fila para codec.
  5. Libere o identificador A/V quando os dados forem consumidos.

Android.media.tv.tuner.dvr

DvrRecorder fornece estes métodos para gravação.

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

A DvrPlayback oferece 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

Exemplo de fluxo para iniciar um registro.

Figura 12. Fluxo para iniciar um registro

  1. 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();
    
  2. 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. }
          }
        }
    };
    
  3. Inicialize OnRecordStatusChangedListener e armazene os dados de 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 e 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

Diagrama de fluxo das interações entre os módulos da HAL do Tuner.

Figura 13. Diagrama das interações entre os módulos HAL do sintonizador

Vinculação do filtro

A HAL Tuner 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. Não é permitido fechar caminhos.
  • O nó raiz é demux.
  • Os filtros funcionam de forma independente.
  • Todos os filtros começam a receber dados.
  • A vinculação do filtro é eliminada 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>)
}

Diagrama de exemplo de vinculação de filtros.

Figura 14. Diagrama de fluxo de uma vinculação de filtros 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 Tuner, TVInput e CAS para apps. O 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 do app. O TRM concede ou revoga o recurso com base na prioridade. O TRM centraliza o gerenciamento de recursos do ATV para transmissão, OTT e DVR.

Interface do TRM

O TRM expõe interfaces AIDL em ITunerResourceManager.aidl para que o framework tuner, MediaCas e TvInputHardwareManager registrem, solicitem ou liberem 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 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 do caso de uso. 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 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 ocorre um conflito de recursos.

Diagrama do processo do mecanismo de recuperação.

Figura 15. Diagrama do mecanismo de recuperação de um conflito entre recursos do Tuner