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 Android TV Tuner, fornecendo APIs Java chamadas do app TV Input Service (TIS).
Os principais objetivos do Media CAS 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.
- Fornecer um framework de CAS no Android que permita a interoperabilidade de OEMs de ATV com vários fornecedores de CAS de maneira consistente.
- Oferecer suporte a vários fornecedores de CAS terceirizados 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, na sigla em inglês) e decodificadores.
- 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 PSI do acesso condicional incluem descritores de CA, ECMs e EMMs. Essas estruturas permitem que o plug-in CAS receba as chaves necessárias para descriptografar os fluxos de conteúdo.
Figura 1. Configuração do sintonizador de hardware
A configuração de hardware pode ter uma camada TEE, como o TrustZone, ilustrado na Figura 1. Se não houver uma camada TEE, um plug-in de cliente CAS poderá se comunicar com os serviços de escada 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 do Media CAS ainda podia ser usado para processar conteúdo baseado em software, como IPTV de multicast/unicast de IP. 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 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 diretamente usando a API nativa.
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).
Figura 2. Configuração de entrada de IPTV, CAS e descrambler 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, o
MediaCodec
não precisa estar envolvido na decodificação. Se a faixa exigir uma decodificação segura, o extrator ainda 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 downstream de 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 desembaralhador seja usado se a faixa for determinada como embaralhada com base na tabela de mapeamento do programa (PMT, na sigla em inglês).
Limitações da configuração de software
Quando a faixa exige uma decodificação segura, o desembaralhador precisa ter cuidado ao permitir que uma operação de decodificação em buffers claros seja feito. Como a decodificação de áudio não segura é 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 ao plug-in que um decodificador seguro é necessário.
Como alternativa, o plug-in precisa ser capaz de vincular uma chave à própria política de segurança de maneira confiável. Caso contrário, o app pode conseguir frames de vídeo facilmente com o descrambador de áudio.
Mesmo quando a sessão exige um decodificador seguro, ela pode receber uma solicitação para gerar uma pequena quantidade de dados para limpar buffers pelo extrator e 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 ele 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 CA contém o ID do sistema de CA, que identifica exclusivamente um fornecedor de CA específico e outros dados específicos do fornecedor. O TIS consulta o CAS de mídia para determinar se existe um plug-in CAS que possa processar o descritor de AC.
Figura 3. Como ajustar o conteúdo do CAS
Se o ID do sistema da AC for compatível, uma instância do Media CAS será criada e os dados particulares do fornecedor do descritor da 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 as 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 CAS determina como adquirir
um EMM para o recurso com base nas informações específicas do fornecedor no
descritor da 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.
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 receber a chave criptografada e 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 descrambelhamento subsequente 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 assinaturas digitais disponíveis no dispositivo.
class MediaCas.PluginDescriptor { public String getName(); public int getSystemId(); } static PluginDescriptor[] enumeratePlugins();
Crie uma instância do Media CAS para o sistema de AC especificado. Isso significa que o framework 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 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 privados para o sistema de AC. Os dados particulares podem vir do descritor de AC, da tabela de acesso condicional ou de fontes fora da banda. Isso não está associado a uma sessão específica.
void setPrivateData(@NonNull byte[] data);
Processa um pacote de EMM.
void processEmm(@NonNull byte[] data, int offset, int length);
Envie um evento para um sistema de AC. O formato do evento é específico do esquema e opaco para o framework.
void sendEvent(int event, int arg, @Nullable byte[] data);
Iniciar uma operação de provisionamento do tipo especificado para um sistema de AC. Quando um dispositivo se inscreve em um serviço de TV por assinatura pela primeira vez, ele precisa ser provisionado primeiro no servidor do 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 ao guia de programação eletrônica (EPG, na sigla em inglês), na sigla em inglês), o app precisa solicitar que os clientes da CA atualizem as chaves de direitos.
void refreshEntitlements(int refreshType);
Feche o objeto do 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 AC de um descritor de AC no PMT, que pode ser da seção de informações do programa ou 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);