Il framework Media conditional Access Systems (Media CAS) fornisce API standard per abilitare servizi di accesso condizionale (CA) su una vasta gamma di hardware per TV digitale, tra cui sistemi via cavo digitale, satellitari, terrestri e sistemi IPTV. Il framework funziona con il framework di input Android TV e il framework del sintonizzatore Android TV, fornendo API Java richiamate dall'app TV Input Service (TIS).
Gli obiettivi principali di Media CAS sono i seguenti.
- Fornire un'API Java pubblica e un framework di plug-in nativo che possa essere utilizzato da OEM e sviluppatori di terze parti per supportare il CAS per la TV broadcast in Android.
- Fornire in Android un framework CAS che consenta agli OEM ATV di interagire con vari fornitori CAS in modo coerente.
- Supporta più fornitori CAS di terze parti utilizzando plug-in nativi. I plug-in CAS possono utilizzare protocolli di rete specifici del fornitore, formati dei messaggi di gestione dei diritti (EMM)/messaggi di controllo dei diritti (ECM) e decodificatori.
- Supporta la sicurezza hardware, ad esempio le scale a pioli.
- Supporta ambienti di esecuzione attendibili (TEE) come TrustZone.
Configurazioni supportate
Configurazione del sintonizzatore hardware
Se l'hardware è responsabile del demultiplexing e della decodifica del flusso di trasporto MPEG, il framework Tuner fornisce dati PSI (Condition-specific Program) all'app TIS per interfacciarsi con sintonizzatori TV basati su hardware.
I dati PSI dell'accesso condizionale includono descrittori CA, ECM ed EMM. Queste strutture consentono al plug-in CAS di ottenere le chiavi necessarie per decriptare gli stream di contenuti.
Figura 1. Configurazione del sintonizzatore hardware
La configurazione hardware potrebbe avere un livello TEE, come TrustZone, illustrato nella Figura 1. Se non è presente un livello TEE, un plug-in client CAS può comunicare con i servizi di struttura a chiavi hardware forniti dalla piattaforma. A causa delle variazioni specifiche del fornitore di queste interfacce, Media CAS non le standardizza.
Configurazione del software
Prima di Android 11, il framework Media CAS poteva essere ancora utilizzato per elaborare contenuti basati su software, come l'IPTV da IP multicast/unicast. L'app TIS è responsabile della creazione delle istanze e del corretto provisioning dell'oggetto Java Media CAS.
L'app potrebbe utilizzare MediaExtractor o altri analizzatori MPEG2-TS per estrarre i dati PSI relativi alle CA, come descrittori CA, ECM ed EMM. Se l'app utilizza il framework MediaExtractor, può delegare la gestione della sessione CAS, ad esempio l'apertura di una sessione e l'elaborazione di EMM/ECM, al framework MediaExtractor. MediaExtractor configura quindi la sessione CAS utilizzando direttamente l'API nativa.
In caso contrario, l'app è responsabile dell'estrazione dei dati PSI relativi alla CA e della configurazione della sessione CAS utilizzando le API Java Media CAS (ad esempio, se l'app utilizza il proprio parser MPEG2-TS).
Figura 2. Configurazione di input IPTV, CAS e decodificatore utilizzando il framework MediaExtractor
Nello scenario dell'estrattore di software, l'estrattore richiede un oggetto decodificatore basato su software o hardware per ogni traccia criptata, indipendentemente dal fatto che la traccia richieda decodificatori sicuri. Ciò è dovuto a quanto segue.
- Se la traccia non richiede una decodifica sicura, l'estrattore decodifica l'unità di accesso per cancellare i buffer ed estrae i campioni come se fossero da un flusso trasparente. In questo modo,
MediaCodec
non deve essere coinvolto nella descrizione. Se la traccia richiede una decodifica sicura, l'estrattore potrebbe comunque necessitare di un decodificatore. Ciò accade quando il flusso di trasporto è criptato a livello di pacchetto di trasporto, dove l'intestazione del flusso elementare pacchettizzato (PES) viene criptata. L'estrattore deve accedere all'intestazione PES per trasmettere determinate informazioni a valle (ad esempio il timestamp della presentazione).
Il decodificatore non viene utilizzato dall'estrattore se lo stream di trasporto è scrambled a livello di pacchetto PES, dove l'intestazione PES viene lasciata vuota. Tuttavia, non è possibile confermare quando avviene lo scrambling finché non arriva il pacchetto criptato effettivo. Per semplicità, supponiamo che venga utilizzato un decodificatore se la traccia è criptata in base alla tabella di mappatura dei programmi (PMT).
Limitazioni della configurazione software
Quando il canale richiede una decodifica sicura, lo scodificatore deve essere attento quando consente un'operazione di decodifica in buffer chiari. Poiché è necessaria una decodifica audio non sicura, se la decodifica video richiede decoder sicuri, deve essere criptata in una sessione diversa dall'audio. L'ECM per la sessione deve segnalare al plug-in che è necessario un decoder sicuro.
In alternativa, il plug-in deve essere in grado di collegare in modo affidabile una chiave al criterio di sicurezza. In caso contrario, l'app può facilmente ottenere frame video con il decodificatore audio.
Anche quando la sessione richiede un decodificatore sicuro, all'estrattore potrebbe essere chiesto di produrre una piccola quantità di dati per svuotare i buffer al fine di elaborare l'intestazione PES. Per impedire a un'app dannosa di fare in modo che il plug-in recuperi l'intera unità di accesso, il plug-in deve analizzare il payload di trasporto per assicurarsi che inizi con un'intestazione PES del tipo di stream appropriato. In caso contrario, il plug-in deve rifiutare la richiesta.
Sequenza di ottimizzazione CA
Durante l'ottimizzazione su un nuovo canale, il modulo TIS si registra per ricevere descrittori CA, ECM ed EMM dal framework PSI Tuner. Un descrittore della CA contiene l'ID di sistema della CA, che identifica in modo univoco uno specifico fornitore della CA e altri dati specifici del fornitore. TIS esegue una query al Media CAS per determinare se esiste un plug-in CAS in grado di gestire il descrittore della CA.
Figura 3. Ottimizzazione del contenuto CAS
Se l'ID sistema CA è supportato, viene creata un'istanza del Media CAS e i dati privati del fornitore dal descrittore CA vengono forniti al plug-in. Successivamente, in Media CAS vengono aperte nuove sessioni per gestire gli stream audio e video. Le sessioni appena aperte ricevono ECM ed EMM per il plug-in.
Flusso di esempio del plug-in CAS
TIS fornisce gli ECM al plug-in CAS utilizzando le API Media CAS. Un file ECM contiene la parola di controllo criptata, che deve essere decriptata utilizzando le informazioni di un EMM. Il plug-in CAS determina come acquisire un EMM per la risorsa in base alle informazioni specifiche del fornitore nel descrittore CA, fornito dal metodo setPrivateData()
.
Gli EMM potrebbero essere pubblicati in banda nello stream di contenuti o fuori banda utilizzando una
richiesta di rete avviata dal plug-in CA. TIS utilizza il metodo processEMM()
per consegnare qualsiasi EMM in banda al plug-in CA.
Se è necessaria una richiesta di rete per ottenere un EMM, il plug-in CA è responsabile di eseguire la transazione di rete con un server di licenze.
Figura 4. Esempio di plug-in CAS per l'elaborazione di EMM ed ECM
Quando viene ricevuto l'EMM, il plug-in CA lo analizza per ottenere la chiave criptata per decriptare la parola di controllo. La chiave EMM criptata e la parola di controllo criptata potrebbero essere caricate in un ladder o in un ambiente attendibile per eseguire la decrittografia della parola di controllo e la successiva descrizione del flusso di contenuti.
API Java Media CAS
L'API Media CAS Java contiene i seguenti metodi.
Elenca tutti i plug-in CA disponibili sul dispositivo.
class MediaCas.PluginDescriptor { public String getName(); public int getSystemId(); } static PluginDescriptor[] enumeratePlugins();
Crea un'istanza Media CAS per il sistema CA specificato. Ciò significa che il framework Media CAS può gestire più sistemi CAS contemporaneamente.
MediaCas(int CA_system_id); MediaCas(@NonNull Context context, int casSystemId, @Nullable String tvInputServiceSessionId, @PriorityHintUseCaseType int priorityHint);
Registra un gestore di eventi e consenti all'app di specificare un gestore di cui viene utilizzato il loop.
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);
Invia i dati privati per il sistema CA. I dati privati possono provenire dal descrittore della CA, dalla tabella di accesso condizionale o dalle origini della banda. Non è associato a una sessione specifica.
void setPrivateData(@NonNull byte[] data);
Elabora un pacchetto EMM.
void processEmm(@NonNull byte[] data, int offset, int length);
Invia un evento a un sistema CA. Il formato dell'evento è specifico per lo schema e opaco per il framework.
void sendEvent(int event, int arg, @Nullable byte[] data);
Avvia un'operazione di provisioning del tipo specificato per un sistema CA. Quando un dispositivo si registra a un servizio di pay TV per la prima volta, deve prima eseguire il provisioning del server CAS. Fornisci un insieme di parametri correlati al dispositivo per il provisioning.
void provision(String provisionString);
Attivare un aggiornamento dei diritti. Quando un utente si abbona a un nuovo canale (ad esempio rispondendo a un annuncio o aggiungendo un canale nella guida elettronica dei programmi (EPG)), l'app dovrebbe essere in grado di indicare ai client CA di aggiornare le chiavi dei diritti.
void refreshEntitlements(int refreshType);
Chiudi l'oggetto Media CAS.
void close();
Apri una sessione.
Session openSession(); Session openSession(@SessionUsage int sessionUsage, @ScramblingMode int scramblingMode);
Chiudi una sessione aperta in precedenza.
void Session#close();
Fornisci i dati privati della CA da un descrittore CA nel PMT, che può essere proveniente dalla sezione Informazioni sul programma o Informazioni ES, a una sessione CAS.
void Session#setPrivateData(@NonNull byte[] sessionId, @NonNull byte[] data);
Elabora un pacchetto ECM per una sessione.
void Session#processEcm(@NonNull byte[] data, int offset, int length);
Recupera l'ID sessione.
byte[] Session#getSessionId();
Invia un evento di sessione a un sistema CA. Il formato dell'evento è specifico per lo schema ed è opaco rispetto al framework.
void Session#sendSessionEvent(int event, int arg, @Nullable byte[] data);