Estrutura CAS

A estrutura de sistemas de acesso condicional de mídia (Media CAS) fornece APIs padrão para habilitar serviços de acesso condicional (CA) em uma variedade de hardware de TV digital, incluindo cabo digital, satélite, sistemas terrestres e sistemas de IPTV. A estrutura funciona com a estrutura de entrada do Android TV e a estrutura do Android TV Tuner , fornecendo APIs Java invocadas do aplicativo TV Input Service (TIS).

Os principais objetivos do Media CAS são os seguintes.

  • Forneça uma API Java pública e uma estrutura de plug-in nativa que possa ser usada por desenvolvedores de terceiros e OEMs para dar suporte ao CAS para transmissão de TV no Android.
  • Forneça uma estrutura de CAS no Android que permita que os OEMs de ATV interoperem com vários fornecedores de CAS de maneira consistente.
  • Suporte a vários fornecedores de CAS de terceiros usando plugins 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 decodificadores.
  • Suporte a segurança de hardware, como escadas de chave.
  • Suporte a ambientes de execução confiáveis ​​(TEEs), como TrustZone.

Configurações compatíveis

Configuração do sintonizador de hardware

Se o hardware for responsável pela desmultiplexação e descodificação do fluxo de transporte MPEG, a estrutura do Tuner fornece dados de informações específicas do programa (PSI) de acesso condicional ao aplicativo TIS para fazer interface com sintonizadores de TV baseados em hardware.

Os dados PSI de acesso condicional incluem descritores de CA, ECMs e EMMs. Essas estruturas permitem que o plug-in 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 TrustZone, que é ilustrada na Figura 1. Se não houver uma camada TEE, um plug-in do cliente CAS pode se comunicar com os serviços de escada de chave 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, a estrutura do Media CAS ainda podia ser usada para processar conteúdo baseado em software, como IPTV de multicast/unicast IP. O aplicativo TIS é responsável por instanciar e provisionar adequadamente o objeto Java do Media CAS.

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

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

Diagrama da configuração do Tuner.

Figura 2. Configuração de entrada de IPTV, CAS e decodificador usando o framework MediaExtractor

No cenário do extrator de software, o extrator requer um objeto decodificador baseado em software ou hardware para cada trilha codificada, independentemente de a trilha exigir decodificadores seguros. Isso se deve ao seguinte.

  • Se a trilha não exigir decodificação segura, o extrator decodifica a unidade de acesso para limpar os buffers e extrai amostras como se fossem de um fluxo limpo. Dessa forma, o MediaCodec não precisa se envolver na decodificação.
  • Se a faixa exigir decodificação segura, o extrator ainda poderá precisar de um decodificador. Isso acontece quando o fluxo de transporte é embaralhado no nível do pacote de transporte, onde o cabeçalho do fluxo elementar empacotado (PES) é embaralhado. O extrator precisa acessar o cabeçalho PES para fazer downstream de certas informações (por exemplo, o timestamp de apresentação).

    O decodificador não é usado pelo extrator se o fluxo de transporte for embaralhado no nível do pacote PES, onde o cabeçalho PES é deixado limpo. No entanto, não é possível confirmar quando o embaralhamento acontece até que o pacote embaralhado real chegue. Para simplificar, suponha que um decodificador seja usado se a faixa for determinada para ser embaralhada com base na tabela de mapeamento de programa (PMT).

Limitações da configuração do software

Quando a faixa requer decodificação segura, o decodificador precisa ser cauteloso ao permitir uma operação de decodificação em buffers limpos. Como a decodificação de áudio insegura é necessária, se a decodificação de vídeo exigir decodificadores seguros, ela deverá ser codificada em uma sessão diferente do áudio. O ECM para a sessão deve sinalizar ao plug-in que um decodificador seguro é necessário.

Como alternativa, o plug-in deve ser capaz de vincular de forma confiável uma chave à sua política de segurança. Caso contrário, o aplicativo pode obter facilmente quadros de vídeo com o decodificador de áudio.

Mesmo quando a sessão requer um decodificador seguro, pode ser solicitado a saída de uma pequena quantidade de dados para limpar buffers pelo extrator para processar o cabeçalho PES. Para evitar que um aplicativo malicioso faça com que o plug-in retorne toda a unidade de acesso, o plug-in precisa analisar a carga útil de transporte para garantir que a carga comece com um cabeçalho PES do tipo de fluxo apropriado. Caso contrário, o plugin deve 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 da estrutura do PSI Tuner. Um descritor de CA contém a ID do sistema de CA, que identifica exclusivamente um fornecedor de CA específico e outros dados específicos de fornecedor. O TIS consulta o Media CAS para determinar se existe um plug-in do CAS que possa lidar com o descritor de CA.

Diagrama de ajuste do conteúdo CAS.

Figura 3. Ajustando o conteúdo do CAS

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

Exemplo de fluxo de plug-in CAS

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

Os EMMs podem ser entregues em banda no fluxo de conteúdo ou fora de banda usando uma solicitação de rede iniciada pelo plug-in CA. O TIS usa o método processEMM() para entregar qualquer EMM em banda ao plug-in CA.

Se for necessária uma solicitação de rede para obter um EMM, o plug-in CA é responsável por realizar 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 CA o analisa para obter 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 chave ou ambiente confiável para executar a descriptografia da palavra de controle e a decodificação subsequente do fluxo de conteúdo.

API Java do CAS de mídia

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

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

    class MediaCas.PluginDescriptor {
      public String getName();
      public int getSystemId();
    }
    static PluginDescriptor[] enumeratePlugins();
    
  • Construa uma instância do Media CAS para o sistema CA especificado. Isso significa que a estrutura do Media CAS pode lidar com vários sistemas CAS simultaneamente.

    MediaCas(int CA_system_id);
    MediaCas(@NonNull Context context, int casSystemId,
             @Nullable String tvInputServiceSessionId,
             @PriorityHintUseCaseType int priorityHint);
    
  • Registre um ouvinte de eventos e permita que o aplicativo especifique um manipulador 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);
    
  • Envie os dados privados para o sistema CA. Os dados privados podem vir do descritor de CA, da tabela de acesso condicional ou de fontes fora de banda. Isso não está associado a uma sessão específica.

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

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

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

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

    void refreshEntitlements(int refreshType);
    
  • Feche o objeto Media CAS.

    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 CA de um descritor de CA no PMT, que pode ser da seção de informações do programa ou de informações do ES, para uma sessão do CAS.

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

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

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

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