Framework CAS

O framework de sistemas de acesso condicional de mídia (Media CAS) fornece APIs padrão para ativar serviços de acesso condicional (CA, na sigla em inglês) em uma variedade de hardware de TV digital, incluindo sistemas digitais a cabo, por satélite, terrestres e IPTV. O framework funciona com o framework de entrada do Android TV e o framework do sintonizador do Android TV, fornecendo APIs Java invocadas pelo app de serviço de entrada de TV (TIS).

Os principais objetivos do CAS de mídia são os seguintes.

  • Fornecer uma API Java pública e um framework de plug-in nativo que podem ser usados por desenvolvedores terceirizados e OEMs para oferecer suporte ao CAS para TV de transmissão no Android.
  • Ofereça um framework de CAS no Android que permita a interoperabilidade de OEMs de ATV com vários fornecedores de CAS de maneira consistente.
  • Oferece suporte a vários fornecedores de CAS de terceiros usando plug-ins nativos. Os plug-ins do CAS podem usar protocolos de rede específicos do fornecedor, formatos de mensagem de gerenciamento de direitos (EMM)/mensagem de controle de direitos (ECM) e descriptografadores.
  • Ofereça suporte à segurança de hardware, como chaves de acesso.
  • Ofereça suporte a ambientes de execução confiáveis (TEEs), como o TrustZone.

Configurações compatíveis

Configuração do sintonizador de hardware

Se o hardware for responsável pela demultiplexação e decodificação do fluxo de transporte MPEG, o framework do sintonizador fornecerá dados de informações específicas de programa (PSI, na sigla em inglês) de acesso condicional ao app TIS para interagir com sintonizadores de TV baseados em hardware.

Os dados de PSI de acesso condicional incluem descrições de CA, ECMs e EMMs. Essas estruturas permitem que o plug-in do CAS obtenha as chaves necessárias para descriptografar os fluxos de conteúdo.

Diagrama da configuração do sintonizador de hardware.

Figura 1. Configuração do sintonizador de hardware

A configuração de hardware pode ter uma camada TEE, como a TrustZone, ilustrada na Figura 1. Se não houver uma camada TEE, um plug-in de cliente CAS poderá se comunicar com os serviços de hierarquia de chaves de hardware fornecidos pela plataforma. Devido a variações específicas do fornecedor dessas interfaces, o Media CAS não as padroniza.

Configuração de software

Antes do Android 11, o framework Media CAS ainda podia ser usado para processar conteúdo baseado em software, como IPTV de IP multicast/unicast. O app TIS é responsável por instanciar e provisionar corretamente o objeto Java do Media CAS.

O app pode usar o MediaExtractor ou outros analisadores MPEG2-TS para extrair dados de PSI relacionados à CA, como descritores de CA, ECMs e EMMs. Se o app usar o framework MediaExtractor, ele poderá delegar o gerenciamento de sessão do CAS, como abrir uma sessão e processar EMM/ECM, ao framework MediaExtractor. O MediaExtractor configura a sessão do CAS usando a API nativa diretamente.

Caso contrário, o app é responsável por extrair os dados de PSI relacionados à CA e configurar a sessão de CAS usando as APIs Java do Media CAS (por exemplo, quando o app usa o próprio analisador MPEG2-TS).

Diagrama da configuração do sintonizador.

Figura 2. Entrada de IPTV, CAS e configuração do decodificador usando o framework MediaExtractor

No cenário do extrator de software, o extrator requer um objeto de decodificador baseado em software ou hardware para cada faixa embaralhada, independente de a faixa exigir decodificadores seguros. Isso ocorre devido ao seguinte.

  • Se a faixa não exigir uma decodificação segura, o extrator descriptografa a unidade de acesso para limpar os buffers e extrai amostras como se fossem de um stream claro. Dessa forma, MediaCodec não precisa estar envolvido na decodificação.
  • Se a faixa exigir uma decodificação segura, o extrator ainda poderá precisar de um decodificador. Isso acontece quando o fluxo de transporte é codificado no nível do pacote de transporte, em que o cabeçalho de fluxo elementar empacotado (PES, na sigla em inglês) é codificado. O extrator precisa acessar o cabeçalho PES para transmitir determinadas informações (por exemplo, o carimbo de data/hora da apresentação).

    O decodificador não é usado pelo extrator se o fluxo de transporte for codificado no nível do pacote PES, em que o cabeçalho PES é deixado claro. No entanto, não é possível confirmar quando a codificação acontece até que o pacote codificado chegue. Para simplificar, suponha que um decodificador seja usado se a faixa for determinada como codificada com base na tabela de mapeamento de programas (PMT).

Limitações da configuração de software

Quando a faixa exige decodificação segura, o decodificador precisa ter cautela ao permitir que uma operação de decodificação seja feita em buffers claros. Como a decodificação de áudio não seguro é necessária, se a decodificação de vídeo exigir decodificadores seguros, ela precisará ser codificada em uma sessão diferente do áudio. O ECM da sessão precisa sinalizar para o plug-in que um decodificador seguro é necessário.

Como alternativa, o plug-in precisa vincular de forma confiável uma chave à política de segurança. Caso contrário, o app pode acessar facilmente frames de vídeo com o decodificador de áudio.

Mesmo quando a sessão exige um decodificador seguro, pode ser necessário que ela gere uma pequena quantidade de dados para limpar buffers pelo extrator para processar o cabeçalho PES. Para evitar que um app malicioso faça o plug-in retornar toda a unidade de acesso, o plug-in precisa analisar o payload de transporte para garantir que o payload comece com um cabeçalho PES do tipo de stream adequado. Caso contrário, o plug-in vai negar a solicitação.

Sequência de ajuste de CA

Ao sintonizar um novo canal, o módulo TIS se registra para receber descritores de CA, ECMs e EMMs do framework do PSI Tuner. Um descritor de AC contém o ID do sistema de AC, que identifica exclusivamente um fornecedor de AC e outros dados específicos do fornecedor. O TIS consulta o CAS de mídia para determinar se existe um plug-in de CAS que possa processar o descritor de AC.

Diagrama de como ajustar o conteúdo do CAS.

Figura 3. Como ajustar o conteúdo do CAS

Se o ID do sistema de AC for aceito, uma instância do Media CAS será criada e os dados privados do fornecedor do descritor de AC serão fornecidos ao plug-in. Em seguida, novas sessões são abertas no Media CAS para processar os fluxos de áudio e vídeo. As sessões recém-abertas recebem ECMs e EMMs para o plug-in.

Exemplo de fluxo do plug-in do CAS

O TIS envia ECMs para o plug-in CAS usando APIs Media CAS. Um ECM contém a palavra de controle criptografada, que precisa ser descriptografada usando informações de um EMM. O plug-in do CAS determina como adquirir um EMM para o recurso com base em informações específicas do fornecedor no descritor de CA, que é fornecido pelo método setPrivateData().

Os EMMs podem ser enviados na banda no stream de conteúdo ou fora da banda usando uma solicitação de rede iniciada pelo plug-in de CA. O TIS usa o método processEMM() para enviar EMMs na banda ao plug-in da CA.

Se uma solicitação de rede for necessária para conseguir um EMM, o plug-in da AC será responsável por executar a transação de rede com um servidor de licença.

Diagrama de um exemplo de CAS.

Figura 4. Exemplo de plug-in CAS para processamento de EMM e ECM

Quando o EMM é recebido, o plug-in da CA o analisa para conseguir a chave criptografada para descriptografar a palavra de controle. A chave EMM criptografada e a palavra de controle criptografada podem ser carregadas em uma escada de chaves ou em um ambiente confiável para realizar a descriptografia da palavra de controle e o desembaralhamento do fluxo de conteúdo.

API Java Media CAS

A API Media CAS Java contém os seguintes métodos.

  • Lista todos os plug-ins de CA disponíveis no dispositivo.

    class MediaCas.PluginDescriptor {
      public String getName();
      public int getSystemId();
    }
    static PluginDescriptor[] enumeratePlugins();
    
  • Crie uma instância de CAS de mídia para o sistema de AC especificado. Isso significa que o framework Media CAS pode processar vários sistemas CAS simultaneamente.

    MediaCas(int CA_system_id);
    MediaCas(@NonNull Context context, int casSystemId,
             @Nullable String tvInputServiceSessionId,
             @PriorityHintUseCaseType int priorityHint);
    
  • Registre um listener de eventos e permita que o app especifique um gerenciador cujo looper seja usado.

    interface MediaCas.EventListener {
      void onEvent(MediaCas, int event, int arg, byte[] data);
      void onSessionEvent(@NonNull MediaCas mediaCas, @NonNull Session session, int event, int arg, @Nullable byte[] data);
      void onPluginStatusUpdate(@NonNull MediaCas mediaCas, @PluginStatus int status, int arg);
      void onResourceLost(@NonNull MediaCas mediaCas);
    }
    void setEventListener(MediaCas.EventListener listener, Handler handler);
    
  • Enviar os dados particulares para o sistema de AC. Os dados particulares podem vir do descritor de AC, da tabela de acesso condicional ou de origens fora da banda. Isso não está associado a uma sessão específica.

    void setPrivateData(@NonNull byte[] data);
    
  • Processar um pacote EMM.

    void processEmm(@NonNull byte[] data, int offset, int length);
    
  • Enviar um evento para um sistema de CA. O formato do evento é específico para o esquema e opaco para a estrutura.

    void sendEvent(int event, int arg, @Nullable byte[] data);
    
  • Inicia uma operação de provisionamento do tipo especificado para um sistema de AC. Quando um dispositivo se inscreve em um serviço de TV paga pela primeira vez, ele precisa ser provisionado para o servidor CAS. Forneça um conjunto de parâmetros relacionados ao dispositivo para provisionamento.

    void provision(String provisionString);
    
  • Acionar uma atualização dos direitos. Quando um usuário se inscreve em um novo canal (por exemplo, respondendo a um anúncio ou adicionando um canal no guia de programas eletrônico (EPG)), o app precisa ser capaz de informar aos clientes da AC para atualizar as chaves de direito.

    void refreshEntitlements(int refreshType);
    
  • Feche o objeto CAS de mídia.

    void close();
    
  • Abra uma sessão.

    Session openSession();
    Session openSession(@SessionUsage int sessionUsage, @ScramblingMode int scramblingMode);
    
  • Feche uma sessão aberta anteriormente.

    void Session#close();
    
  • Forneça os dados privados da AC de um descritor de AC no PMT, que pode ser da seção de informações do programa ou de informações da ES, para uma sessão de CAS.

    void Session#setPrivateData(@NonNull byte[] sessionId, @NonNull byte[] data);
    
  • Processa um pacote ECM para uma sessão.

    void Session#processEcm(@NonNull byte[] data, int offset, int length);
    
  • Receba o ID da sessão.

    byte[] Session#getSessionId();
    
  • Enviar um evento de sessão para um sistema de CA. O formato do evento é específico para o esquema e é opaco para o framework.

    void Session#sendSessionEvent(int event, int arg, @Nullable byte[] data);