メディア条件付きアクセス システム (Media CAS) フレームワークは、デジタル ケーブル、衛星、地上波システム、IPTV システムなど、さまざまなデジタル TV ハードウェアで条件付きアクセス (CA) サービスを有効にする標準 API を提供します。このフレームワークは、 Android TV 入力フレームワークおよびAndroid TV チューナー フレームワークと連携し、TV 入力サービス (TIS) アプリから呼び出される Java API を提供します。
メディア CAS の主な目的は次のとおりです。
- サードパーティの開発者や OEM が Android でテレビ放送用の CAS をサポートするために使用できる、パブリック Java API とネイティブ プラグイン フレームワークを提供します。
- ATV OEM がさまざまな CAS ベンダーと一貫した方法で相互運用できるようにする、Android 内の CAS フレームワークを提供します。
- ネイティブ プラグインを使用して、複数のサードパーティ CAS ベンダーをサポートします。 CAS プラグインは、ベンダー固有のネットワーク プロトコル、資格管理メッセージ (EMM)/資格制御メッセージ (ECM) 形式、およびデスクランブラーを使用する場合があります。
- キーラダーなどのハードウェア セキュリティをサポートします。
- TrustZone などの信頼できる実行環境 (TEE) をサポートします。
サポートされている構成
ハードウェア チューナーの構成
ハードウェアが MPEG トランスポート ストリームの逆多重化とデスクランブリングを担当する場合、チューナー フレームワークは、ハードウェア ベースの TV チューナーとインターフェイスするために、条件付きアクセス プログラム固有情報 (PSI) データを TIS アプリに提供します。
条件付きアクセス PSI データには、CA 記述子、ECM、および EMM が含まれます。これらの構造により、CAS プラグインはコンテンツ ストリームの復号化に必要なキーを取得できます。
図 1.ハードウェア チューナーの構成
ハードウェア構成には、図 1 に示されている TrustZone などの TEE レイヤーが含まれている場合があります。TEE レイヤーがない場合、CAS クライアント プラグインは、プラットフォームによって提供されるハードウェア キー ラダー サービスと通信できます。これらのインターフェイスにはベンダー固有のバリエーションがあるため、Media CAS はそれらを標準化していません。
ソフトウェア構成
Android 11 より前のバージョンでは、Media CAS フレームワークを使用して、IP マルチキャスト/ユニキャストからの IPTV などのソフトウェア ベースのコンテンツを処理できました。 TIS アプリは、Media CAS Java オブジェクトのインスタンス化と適切なプロビジョニングを担当します。
アプリは、MediaExtractor またはその他の MPEG2-TS パーサーを使用して、CA 記述子、ECM、EMM などの CA 関連の PSI データを抽出する場合があります。アプリがフレームワーク MediaExtractor を使用する場合、セッションの開始や EMM/ECM の処理などの CAS セッション管理をフレームワーク MediaExtractor に委任できます。 MediaExtractor は、ネイティブ API を直接使用して CAS セッションを構成します。
それ以外の場合、アプリは、CA 関連の PSI データを抽出し、Media CAS Java API を使用して CAS セッションを構成する必要があります (たとえば、アプリが独自の MPEG2-TS パーサーを使用する場合)。
図 2.フレームワーク MediaExtractor を使用した IPTV 入力、CAS、およびデスクランブラーの構成
ソフトウェア エクストラクタのシナリオでは、エクストラクタは、トラックがセキュア デコーダを必要とするかどうかに関係なく、スクランブルされたトラックごとにソフトウェアまたはハードウェア ベースのデスクランブラ オブジェクトを必要とします。これは以下の理由による。
- トラックが安全なデコードを必要としない場合、エクストラクタはアクセス ユニットをデスクランブルしてバッファをクリアし、クリア ストリームからのようにサンプルを抽出します。この方法では、
MediaCodec
がデスクランブルに関与する必要はありません。 トラックが安全なデコードを必要とする場合でも、エクストラクタにはデスクランブラが必要になる場合があります。これは、トランスポート ストリームがトランスポート パケット レベルでスクランブルされている場合に発生し、パケット化されたエレメンタリ ストリーム (PES) ヘッダーがスクランブルされます。エクストラクタは、ダウンストリームの特定の情報 (プレゼンテーションのタイムスタンプなど) に PES ヘッダーにアクセスする必要があります。
トランスポート ストリームが PES ヘッダーがクリアされている PES パケット レベルでスクランブルされている場合、エクストラクタはデスクランブラを使用しません。ただし、実際にスクランブルされたパケットが到着するまで、スクランブルがいつ発生したかを確認することはできません。簡単にするために、トラックがプログラム マッピング テーブル (PMT) に基づいてスクランブルされていると判断された場合、デスクランブラーが使用されると仮定します。
ソフトウェア構成の制限
トラックが安全なデコードを必要とする場合、デスクランブラーは、デスクランブル操作をクリア バッファーに入れる際に注意する必要があります。安全でないオーディオのデコードが必要なため、ビデオのデコードに安全なデコーダが必要な場合は、オーディオとは別のセッションでスクランブルする必要があります。セッションの ECM は、安全なデコーダーが必要であることをプラグインに通知する必要があります。
または、プラグインはキーをセキュリティ ポリシーに確実に関連付けることができなければなりません。それ以外の場合、アプリはオーディオ デスクランブラーを使用してビデオ フレームを簡単に取得できます。
セッションが安全なデコーダーを必要とする場合でも、PES ヘッダーを処理するためにエクストラクターによってバッファーをクリアするために少量のデータを出力するように求められる場合があります。悪意のあるアプリがプラグインにアクセス ユニット全体を返させないようにするために、プラグインはトランスポート ペイロードを解析して、ペイロードが適切なストリーム タイプの PES ヘッダーで始まることを確認する必要があります。それ以外の場合、プラグインはリクエストを拒否する必要があります。
CA チューニング シーケンス
新しいチャネルにチューニングする場合、TIS モジュールは、PSI チューナー フレームワークから CA 記述子、ECM、および EMM を受信するように登録します。 CA 記述子には、特定の CA ベンダーおよびその他のベンダー固有のデータを一意に識別する CA システム ID が含まれています。 TIS は Media CAS に問い合わせて、CA 記述子を処理できる CAS プラグインが存在するかどうかを判断します。
図 3. CAS コンテンツのチューニング
CA システム ID がサポートされている場合、メディア 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 キーと暗号化されたコントロール ワードは、キー ラダーまたは信頼できる環境にロードされ、コントロール ワードの復号化とそれに続くコンテンツ ストリームのデスクランブルが実行される場合があります。
メディア 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();
プログラム情報または ES 情報セクションからの PMT の CA 記述子から CA プライベート データを 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);