媒體條件存取系統 (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 之前,媒體 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
在軟體擷取器的情況下,無論追蹤是否為安全解碼器呼叫,擷取器都必須為每個打散軌跡取得軟體或硬體型解碼器物件。原因如下:
- 如果音軌不需要安全解碼,擷取器會解碼存取單位以清除緩衝區並擷取樣本,就像使用清除串流一樣。如此一來,
MediaCodec
就不需參與欺騙行為。 如果音軌需要安全解碼,擷取器可能仍需要解碼器。如果傳輸串流在傳輸封包層級經過加密,而封包化的基本串流 (PES) 標頭是亂碼,就會發生這種情況。擷取器需要存取 PES 標頭,才能取得下游的特定資訊 (例如呈現時間戳記)。
如果傳輸串流是在 PES 封包層級解密,則擷取器不會使用解密器,因為 PES 標頭會保持清除狀態。不過,實際的雜訊處理作業發生的時間,必須等到實際的雜訊處理封包到達後才能確認。為了簡單起見,假設系統會在根據節目對應表 (PMT) 判定音軌是否經過雜訊處理時,使用解密器。
軟體設定的限制
如果音軌需要透過安全解碼,在讓解散作業進入清除緩衝區時,必須謹慎小心。由於需要不安全的音訊解碼,如果影片解碼需要安全的解碼器,則應在與音訊不同的工作階段中進行雜湊處理。工作階段的 ECM 必須向外掛程式傳送需要安全解碼器的信號。
或者,外掛程式必須能夠可靠地將金鑰與其安全性政策綁定。否則,應用程式可以輕鬆透過音訊解密器取得影像影格。
即使工作階段需要安全解碼器,也可能會要求輸出少量資料,以便擷取器清除緩衝區,進而處理 PES 標頭。為了避免惡意應用程式傳回整個存取單元,外掛程式必須剖析傳輸酬載,確保酬載以適當串流類型的 PES 標頭開頭。否則,外掛程式應拒絕要求。
CA 調整序列
當您切換至新頻道時,TIS 模組會註冊接收來自 PSI Tuner 架構的 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。
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 系統建構媒體 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 描述元提供給 CAS 工作階段,該描述元可來自節目資訊或 ES 資訊部分。
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);