CAS フレームワーク

Media 限定受信システム(Media CAS)フレームワークは、デジタル ケーブル、衛星、地上波システム、IPTV システムを含め、さまざまなデジタル TV ハードウェアで限定受信(CA)サービスを利用できるようにする標準 API を提供します。このフレームワークは、Android TV 入力フレームワークおよび Android TV チューナー フレームワークと連携し、TV 入力サービス(TIS)アプリから呼び出される Java API を提供します。

Media CAS の主な目的は次のとおりです。

  • 公開 Java API とネイティブ プラグイン フレームワークを提供します。サードパーティ デベロッパーと OEM は、Android のテレビ放送で CAS をサポートするためにこれを使用できます。
  • ATV OEM がさまざまな CAS ベンダーと一貫した方法で相互運用できる CAS フレームワークを Android 内に提供します。
  • ネイティブ プラグインを使用して、複数のサードパーティ CAS ベンダーをサポートします。CAS プラグインでは、ベンダー固有のネットワーク プロトコル、資格管理メッセージ(EMM)/ 資格制御メッセージ(ECM)形式、デスクランブラを使用できます。
  • キーラダーなどのハードウェア セキュリティをサポートします。
  • TrustZone などの高信頼実行環境(TEE)をサポートします。

サポートされている構成

ハードウェア チューナー構成

ハードウェアが MPEG トランスポート ストリームの逆多重化とスクランブル解除を担当する場合、Tuner フレームワークは、ハードウェア ベースの TV チューナーとのインターフェースとして、TIS アプリに限定受信プログラム固有の情報(PSI)データを提供します。

限定受信 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 プラグインが存在するかどうかを確認します。

CAS コンテンツのチューニングの図。

図 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 プラグインは、ライセンス サーバーとのネットワーク トランザクションを行います。

CAS の例の図

図 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);
    
  • イベント リスナーを登録し、looper を使用するハンドラをアプリが指定できるようにします。

    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();
    
  • PMT の CA 記述子(プログラム情報または ES 情報セクション)からの 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);