媒體條件存取系統 (Media CAS) 架構提供標準 API,可在各種數位電視硬體 (包括數位有線、衛星、地面系統和 IPTV 系統) 上啟用條件存取 (CA) 服務。這個架構可與 Android TV 輸入架構和 Android TV 調諧器架構搭配使用,提供從 TV 輸入服務 (TIS) 應用程式叫用的 Java API。
Media CAS 的主要目標如下:
- 提供公開的 Java API 和原生外掛程式架構,供第三方開發人員和原始設備製造商 (OEM) 使用,以便在 Android 中支援電視廣播 CAS。
- 在 Android 中提供 CAS 架構,讓 ATV 原始設備製造商 (OEM) 以一致的方式與各種 CAS 供應商互動。
- 支援使用原生外掛程式支援多個第三方 CAS 供應商。CAS 外掛程式可能會使用供應商專屬網路通訊協定、授權管理訊息 (EMM)/授權控制訊息 (ECM) 格式和解密器。
- 支援硬體安全性,例如金鑰階梯。
- 支援 TrustZone 等受信任的執行環境 (TEE)。
支援的設定
硬體調諧器設定
如果硬體負責 MPEG 傳輸串流的解調和解密,Tuner 架構會將條件存取的節目專屬資訊 (PSI) 資料提供給 TIS 應用程式,以便與硬體電視調諧器連接。
條件存取權 PSI 資料包括 CA 描述符、ECM 和 EMM。這些結構可讓 CAS 外掛程式取得解密內容串流所需的金鑰。
圖 1. 硬體調諧器設定
硬體設定可能會有 TEE 層,例如 TrustZone,如圖 1 所示。如果沒有 TEE 層,CAS 用戶端外掛程式可以與平台提供的硬體金鑰階梯服務通訊。由於這些介面有廠商專屬的差異,Media CAS 並未將其標準化。
軟體設定
在 Android 11 之前,Media CAS 架構仍可用於處理以軟體為基礎的內容,例如來自 IP 多播/單播的 IPTV。TIS 應用程式負責例項化並正確佈建 Media CAS Java 物件。
應用程式可能會使用 MediaExtractor 或其他 MPEG2-TS 剖析器,擷取 CA 相關的 PSI 資料,例如 CA 描述符、ECM 和 EMM。如果應用程式使用 MediaExtractor 架構,則可將 CAS 工作階段管理作業 (例如開啟工作階段和處理 EMM/ECM) 委派給 MediaExtractor 架構。接著,MediaExtractor 會直接使用原生 API 設定 CAS 工作階段。
否則,應用程式必須負責擷取與 CA 相關的 PSI 資料,並使用 Media CAS Java API 設定 CAS 工作階段 (例如,當應用程式使用自己的 MPEG2-TS 剖析器時)。
圖 2. 使用 MediaExtractor 架構設定 IPTV 輸入、CAS 和 descrambler
在軟體擷取器情境中,無論音軌是否呼叫安全解碼器,擷取器都需要為每個雜訊的音軌提供軟體或硬體的 descrambler 物件。原因如下:
- 如果音軌不需要安全解碼,擷取器會解密存取單位,清除緩衝區,並從清晰的串流中擷取樣本。這樣一來,
MediaCodec
就不需要參與解密作業。 如果音軌需要安全解碼,擷取器可能仍需要解密器。當傳輸串流在傳輸封包層級進行雜湊時,就會發生這種情況,而封包化基本串流 (PES) 標頭也會雜湊。擷取器需要存取 PES 標頭,才能取得特定的下游資訊 (例如呈現時間戳記)。
如果傳輸串流是在 PES 封包層級解密,則擷取器不會使用解密器,因為 PES 標頭會保持清除狀態。不過,實際的雜訊處理作業發生的時間,必須等到實際的雜訊處理封包到達後才能確認。為了簡單起見,假設系統會在根據節目對應表 (PMT) 判定音軌是否經過雜訊處理後,使用解密器。
軟體設定的限制
如果音軌需要安全解碼,解密器在將解密作業放入清除緩衝區時,必須小心謹慎。由於需要不安全的音訊解碼,如果影片解碼需要安全的解碼器,則應在與音訊不同的工作階段中進行雜湊。工作階段的 ECM 必須向外掛程式發出安全解碼器必要性的信號。
或者,外掛程式必須能夠可靠地將金鑰與其安全性政策綁定。否則,應用程式可以輕鬆透過音訊解密器取得影格。
即使工作階段需要安全解碼器,也可能會要求輸出少量資料,以便擷取器清除緩衝區,進而處理 PES 標頭。為避免惡意應用程式讓外掛程式傳回整個存取單位,外掛程式需要剖析傳輸酬載,確保酬載以適當串流類型的 PES 標頭開頭。否則,外掛程式應拒絕要求。
CA 調整序列
當您切換至新頻道時,TIS 模組會註冊接收來自 PSI 調整器架構的 CA 描述元、ECM 和 EMM。CA 描述元件包含 CA 系統 ID,可用於明確識別特定 CA 供應商和其他供應商專屬資料。TIS 會查詢 Media CAS,判斷是否有 CAS 外掛程式可處理 CA 描述元。
圖 3. 調整 CAS 內容
如果支援 CA 系統 ID,系統會建立 Media CAS 的例項,並將 CA 描述項中的供應商私人資料提供給外掛程式。接著,Media CAS 會開啟新的工作階段,以便處理音訊和視訊串流。新開啟的工作階段會接收外掛程式的 ECM 和 EMM。
CAS 外掛程式流程範例
TIS 會使用 Media CAS API 將 ECM 傳送至 CAS 外掛程式。ECM 包含加密的控制字,需要使用 EMM 的資訊進行解密。CAS 外掛程式會根據 setPrivateData()
方法提供的 CA 描述符中供應商專屬資訊,決定如何取得資產的 EMM。
內容管理模組可能會在內容串流中以頻帶內方式傳送,或是使用由 CA 外掛程式啟動的網路要求以頻帶外方式傳送。TIS 會使用 processEMM()
方法,將任何頻帶內 EMM 傳送至 CA 外掛程式。
如果取得 EMM 需要網路要求,CA 外掛程式就會負責與授權伺服器執行網路交易。
圖 4. 用於處理 EMM 和 ECM 的 CAS 外掛程式範例
收到 EMM 後,CA 外掛程式會剖析 EMM,取得用於解密控制字的加密金鑰。加密的 EMM 金鑰和加密的控制字詞可能會載入至金鑰階梯或信任環境,以便執行控制字詞解密作業,並隨後對內容串流進行解密。
Media CAS Java API
Media CAS Java API 包含下列方法。
列出裝置上所有可用的 CA 外掛程式。
class MediaCas.PluginDescriptor { public String getName(); public int getSystemId(); } static PluginDescriptor[] enumeratePlugins();
為指定的 CA 系統建構 Media CAS 例項。也就是說,Media CAS 架構可同時處理多個 CAS 系統。
MediaCas(int CA_system_id); MediaCas(@NonNull Context context, int casSystemId, @Nullable String tvInputServiceSessionId, @PriorityHintUseCaseType int priorityHint);
註冊事件監聽器,並允許應用程式指定使用該迴圈的處理常式。
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);
傳送 CA 系統的私人資料。私人資料可來自 CA 描述符、條件存取表或非頻道來源。這不會與特定工作階段建立關聯。
void setPrivateData(@NonNull byte[] data);
處理 EMM 封包。
void processEmm(@NonNull byte[] data, int offset, int length);
將事件傳送至 CA 系統。事件格式是特定於配置,對架構而言是不可見的。
void sendEvent(int event, int arg, @Nullable byte[] data);
為 CA 系統啟動指定類型的佈建作業。裝置首次訂閱付費電視服務時,必須先將裝置佈建至 CAS 伺服器。為裝置提供一組相關參數,以便裝置進行佈建。
void provision(String provisionString);
觸發授權重新整理作業。當使用者訂閱新頻道 (例如回應廣告或在電子節目指南 (EPG) 中新增頻道) 時,應用程式應可通知 CA 用戶端重新整理授權金鑰。
void refreshEntitlements(int refreshType);
關閉 Media CAS 物件。
void close();
開啟工作階段。
Session openSession(); Session openSession(@SessionUsage int sessionUsage, @ScramblingMode int scramblingMode);
關閉先前開啟的工作階段。
void Session#close();
將 CA 私人資料從 PMT 中的 CA 描述符 (可來自節目資訊或 ES 資訊部分) 提供給 CAS 工作階段。
void Session#setPrivateData(@NonNull byte[] sessionId, @NonNull byte[] data);
處理工作階段的 ECM 封包。
void Session#processEcm(@NonNull byte[] data, int offset, int length);
取得工作階段 ID。
byte[] Session#getSessionId();
將工作階段事件傳送至 CA 系統。事件格式會依據結構定義而定,對架構而言是不可見的。
void Session#sendSessionEvent(int event, int arg, @Nullable byte[] data);