保護されたコンテンツのワークフローについて

Flash Player 10.1 以降、Adobe AIR 2.0 以降

重要 :Flash Player 11.5 以降は、Adobe Access モジュールと統合されているので、更新手順( SystemUpdater.update(SystemUpdaterType.DRM) の呼び出し)を行う必要はありません。この更新手順が不要となるのは、次のブラウザーとプラットフォームです。

  • Flash Player 11.5 ActiveX コントロール(Windows 8 上の Internet Explorer を除くすべてのプラットフォーム)。Intel プロセッサ

  • Flash Player 11.5 プラグイン(すべてのブラウザー)。

  • Adobe AIR(デスクトップおよびモバイル)。

つまり、次の場合は、更新手順を行う必要があります。

  • Windows 8 上の Internet Explorer。Intel プロセッサ

  • Flash Player 11.4 以前。ただし、Google Chrome 22 以降(すべてのプラットフォーム)および Google Chrome 21 以降(Windows)の場合は更新手順を行う必要はありません。

注意: Flash Player 11.5 以降を備えたシステムでも、 SystemUpdater.update(SystemUpdaterType.DRM) を安全に呼び出すことはできますが、何もダウンロードされません。

次の高レベルなワークフローは、保護されたコンテンツをアプリケーションが取得して再生する方法を示しています。ワークフローでは、Adobe Access によって保護されたコンテンツを再生するようにアプリケーションが設計されていることが前提です。

  1. コンテンツメタデータを取得します。

  2. 必要に応じて、Flash Player を更新します。

  3. ライセンスをローカルに利用できるかどうか確認します。利用できる場合は、読み込んで手順 7 に移動します。利用できない場合は、手順 4 に移動します。

  4. 認証が必要かどうかを確認します。必要でない場合は、手順 7 に移動します。

  5. 認証が必要な場合は、ユーザーから認証資格情報を取得し、ライセンスサーバーに渡します。

  6. ドメイン登録が必要な場合は、ドメインに参加します(AIR 3.0 以降)。

  7. 認証に成功したら、サーバーからライセンスをダウンロードします。

  8. コンテンツを再生します。

エラーが発生せず、ユーザーがコンテンツの表示を許可された場合は、NetStream オブジェクトが DRMStatusEvent オブジェクトを送出します。その後、アプリケーションが再生を開始します。DRMStatusEvent オブジェクトは、関連する証明書の情報を保持し、それによってユーザーのポリシーと権限を識別します。例えば、コンテンツをオフラインで利用できるようにするかどうかや、ライセンスの有効期限に関する情報を保持します。アプリケーションは、このデータを使用してユーザーにポリシーのステータスを通知します。例えば、アプリケーションは、コンテンツをユーザーが表示できる残りの日数をステータスバーに表示できます。

ユーザーにオフラインアクセスが許可される場合、証明書がキャッシュされ、暗号化されたコンテンツがユーザーのマシンにダウンロードされます。コンテンツは、ライセンスのキャッシュ期間として定義される間はアクセス可能になります。イベントの detail プロパティには、「 DRM.voucherObtained 」が含まれます。アプリケーションは、オフラインでコンテンツを使用できるようにするために、コンテンツをローカルに格納する場所を決定します。DRMManager クラスを使用して証明書を事前に読み込むこともできます。

注意: 証明書のキャッシュおよび事前読み込みは、AIR および Flash Player でサポートされています。ただし、暗号化されたコンテンツのダウンロードおよび保存は、AIR でのみサポートされています。

エラーイベントを明示的に処理する責務はアプリケーション側にあります。このイベントには、ユーザーが有効な資格情報を入力した場合が含まれますが、暗号化されたコンテンツを保護する証明書はコンテンツに対するアクセスを制限します。例えば、認証されたユーザーは、権利に対して支払いが済んでいない場合、コンテンツにアクセスすることはできません。また、同じ発行者による 2 人の登録メンバーのうち 1 人しか支払いを済ませていないコンテンツを、その 2 人が共有しようとするような場合も、このイベントが発生します。アプリケーションがユーザーに対してエラーを通知し、代替手段を提示する必要があります。一般的な代替手段として、表示する権利の登録およびその権利に対する支払いの方法について説明することが挙げられます。

詳細な API ワークフロー

このワークフローでは、保護されたコンテンツのワークフローをより詳細に示します。このワークフローは、Adobe Access によって保護されたコンテンツを再生するために使用される特定の API を示しています。

  1. URLLoader オブジェクトを使用して、保護されたコンテンツのメタデータファイルのバイトを読み込みます。このオブジェクトを metadata_bytes などの変数に設定します。

    Adobe Access によって制御されるすべてのコンテンツは、Adobe Access メタデータを持ちます。コンテンツがパッケージ化されると、このメタデータは別のメタデータファイル(.metadata)として、コンテンツと共に保存できるようになります。詳しくは、Adobe Access のマニュアルを参照してください。

  2. DRMContentData インスタンスを作成します。このコードを次の try-catch ブロックに配置します。

    new DRMContentData( metadata_bytes )

    ここで、 metadata_bytes は手順 1 で取得した URLLoader オブジェクトです。

  3. (Flash Player のみ)ランタイムは、Adobe Access モジュールをチェックします。見つからない場合は、DRMErrorEvent エラーコード 3344 または DRMErrorEvent エラーコード 3343 の IllegalOperationError がスローされます。

    このエラーを処理するには、SystemUpdater API を使用して Adobe Access モジュールをダウンロードします。このモジュールのダウンロード後、SystemUpdater オブジェクトは COMPLETE イベントを送出します。これには、このイベントが送出されたときに手順 2 に戻る、このイベントのイベントリスナーが含まれます。これらの手順について、次のコードで示します。

    flash.system.SystemUpdater.addEventListener(Event.COMPLETE, updateCompleteHandler); 
    flash.system.SystemUpdater.update(flash.system.SystemUpdaterType.DRM)
    private function updateCompleteHandler (event:Event):void { 
        /*redo step 2*/ 
        drmContentData = new DRMContentData(metadata_bytes); 
    } 

    プレーヤーそのものを更新する必要がある場合は、ステータスイベントが送出されます。このイベントの処理について詳しくは、 更新イベントの監視 を参照してください。

    注意: AIR アプリケーションでは、AIR インストーラーは Adobe Access モジュールの更新および必要なランタイム更新を処理します。
  4. DRMManager オブジェクトから送出される DRMStatusEvent および DRMErrorEvent を監視するリスナーを次のように作成します。

    DRMManager.addEventListener(DRMStatusEvent.DRM_STATUS, onDRMStatus); 
    DRMManager.addEventListener(DRMErrorEvent.DRM_ERROR, onDRMError);

    DRMStatusEvent リスナーで、証明書が有効である(null でない)ことを確認します。DRMErrorEvent リスナーで、DRMErrorEvents を処理します。 DRMStatusEvent クラスの使用 および DRMErrorEvent クラスの使用 を参照してください。

  5. コンテンツの再生に必要な証明書(ライセンス)を読み込みます。

    最初に、ローカルに保存されたライセンスを読み込んで、コンテンツの再生を試みます。

    DRMManager.loadvoucher(drmContentData, LoadVoucherSetting.LOCAL_ONLY)

    読み込みが完了すると、DRMManager オブジェクトは DRMStatusEvent.DRM_Status を送出します。

  6. DRMVoucher オブジェクトが null でない場合、証明書は有効です。手順 13 に進みます。

  7. DRMVoucher オブジェクトが null の場合は、このコンテンツに対してポリシーで要求されている認証方法を確認します。 DRMContentData.authenticationMethod プロパティを使用します。

  8. 認証方法が ANONYMOUS の場合は、手順 13 に進みます。

  9. 認証方法が USERNAME_AND_PASSWORD の場合、アプリケーションはユーザーが資格情報を入力するためのメカニズムを提供する必要があります。その資格情報をライセンスサーバーに渡してユーザーを認証します。

    DRMManager.authenticate(metadata.serverURL, metadata.domain, username, password)

    認証に失敗した場合、DRMManager は DRMAuthenticationErrorEvent を送出し、認証に成功した場合は DRMAuthenticationCompleteEvent を送出します。これらのイベントのリスナーを作成します。

  10. 認証方法が UNKNOWN の場合、カスタム認証方法を使用する必要があります。この場合、コンテンツプロバイダーは、ActionScript 3.0 API を使用せずに、帯域外で認証が行われるよう手配しておく必要があります。カスタム認証手順では、 DRMManager.setAuthenticationToken() メソッドに渡すことができる認証トークンを生成する必要があります。

  11. 認証が失敗した場合、アプリケーションは手順 9 に戻る必要があります。アプリケーションに、認証の失敗が繰り返されたときにそれを処理し、制限するメカニズムがあることを確認します。例えば、3 回の試行後に、認証に失敗してコンテンツを表示できないことを示すメッセージをユーザーに表示します。

  12. ユーザーに資格情報の入力を求めるのではなく、保存されたトークンを使用するには、 DRMManager.setAuthenticationToken() メソッドを使用してトークンを設定します。次に、ライセンスサーバーからライセンスをダウンロードし、手順 8 のようにコンテンツを再生します。

  13. (オプション)認証に成功した場合は、認証トークンをキャプチャできます。これは、メモリにキャッシュされるバイト配列です。このトークンは、 DRMAuthenticationCompleteEvent.token プロパティを使用して取得します。認証トークンを保存および使用し、ユーザーが繰り返しこのコンテンツの資格情報を入力しなくても済むようにすることができます。ライセンスサーバーは、認証トークンの有効期限を決定します。

  14. 認証に成功した場合は、次のようにライセンスサーバーからライセンスをダウンロードします。

    DRMManager.loadvoucher(drmContentData, LoadVoucherSetting.FORCE_REFRESH)

    読み込みが完了すると、DRMManager オブジェクトは DRMStatusEvent.DRM_STATUS を送出します。このイベントを監視し、これが送出されたら、コンテンツを再生できます。

  15. NetStream オブジェクトを作成し、その play() メソッドを呼び出して、ビデオを再生します。

    stream = new NetStream(connection); 
    stream.addEventListener(DRMStatusEvent.DRM _STATUS, drmStatusHandler); 
    stream.addEventListener(DRMErrorEvent.DRM_ERROR, drmErrorHandler); 
    stream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler); 
    stream.client = new CustomClient(); 
    video.attachNetStream(stream); 
    stream.play(videoURL); 

DRMContentData およびセッションオブジェクト

DRMContentData が作成されると、Flash Player DRM モジュールを参照するセッションオブジェクトとして使用されます。この DRMContentData を受信するすべての DRMManager API は、特定の DRM モジュールを使用します。ただし、 DRMContentData を使用しない DRMManager API が 2 つあります。異なる規則を以下に示します。
  1. authenticate()

  2. setAuthenticationToken()

DRMContentData と関連がないので、これらの DRMManager API を呼び出すと、ディスクにある最新の DRM モジュールが使用されます。これは、アプリケーションの DRM ワークフローの途中で DRM モジュールが更新される場合に問題となることがあります。次のシナリオについて考えます。
  1. アプリケーションが DRMContentData オブジェクト contentData1 を作成します。このオブジェクトは、DRM モジュールとして AdobeCP1 を使用します。

  2. アプリケーションが DRMManager.authenticate(contentData1.serverURL,...) メソッドを呼び出します。

  3. アプリケーションが DRMManager.loadVoucher(contentData1, ...) メソッドを呼び出します。

アプリケーションが手順 2 に到達するまでに DRM モジュールの更新が発生した場合、 DRMManager.authenticate() メソッドは、最終的に DRM モジュールとして AdobeCP2 を使用して認証します。手順 3 の loadVoucher() メソッドは、DRM モジュールとしてまだ AdobeCP1 を使用しているので失敗します。他のアプリケーションが DRM モジュールの更新を呼び出すことで、更新が発生する可能性があります。このようなシナリオを回避するには、アプリケーション起動時に DRM モジュールの更新を呼び出します。

DRM 関連イベント

保護されたコンテンツの再生をアプリケーションが試みたときに、ランタイムは次に示す多数のイベントを送出します。

  • DRMDeviceGroupErrorEvent(AIR のみ)、DRMManager によって送出

  • DRMAuthenticateEvent(AIR のみ)、NetStream によって送出

  • DRMAuthenticationCompleteEvent、DRMManager によって送出

  • DRMAuthenticationErrorEvent、DRMManager によって送出

  • DRMErrorEvent、NetStream および DRMManager によって送出

  • DRMStatusEvent、NetStream および DRMManager によって送出

  • StatusEvent

  • NetStatusEvent. 更新イベントの監視 を参照してください。

Adobe Access によって保護されるコンテンツをサポートするために、DRM イベントを処理するイベントリスナーを追加します。

オフライン再生用の証明書の事前読み込み

Adobe Access によって保護されているコンテンツの再生に必要な証明書(ライセンス)を事前に読み込むことができます。証明書を事前に読み込むことにより、ユーザーは、アクティブなインターネット接続の有無にかかわらず、コンテンツを表示できるようになります(ただし、事前読み込みのプロセスではインターネット接続が必要です)。証明書を事前に読み込むには、NetStream クラスの preloadEmbeddedMetadata() メソッドと、DRMManager クラスを使用します。AIR 2.0 以降では、DRMContentData オブジェクトを使用して証明書を事前に直接読み込むことができます。このテクニックがお勧めなのは、コンテンツとは無関係に DRMContentData オブジェクトを更新できるためです( preloadEmbeddedData() メソッドはコンテンツから DRMContentData をフェッチします)。

DRMContentData の使用

次の手順は、DRMContentData オブジェクトを使用して、保護されたメディアファイルに対して証明書を事前に読み込むためのワークフローを示しています。

  1. パッケージ化されたコンテンツのバイナリメタデータを取得します。Adobe Access Java Reference Packager を使用している場合、このメタデータファイルは自動的に .metadata 拡張子を使用して生成されます。例えば、URLLoader クラスを使用してこのメタデータをダウンロードできます。

  2. DRMContentData オブジェクトを作成し、メタデータをコンストラクター関数に渡します。

    var drmData:DRMContentData = new DRMContentData( metadata );
  3. 以降の手順は、 保護されたコンテンツのワークフローについて で説明しているワークフローと同じです。

preloadEmbeddedMetadata() の使用

次の手順では、 preloadEmbeddedMetadata() を使用して、DRM で保護されたメディアファイルの証明書を事前に読み込むためのワークフローを示します。

  1. メディアファイルをダウンロードして保存します(DRM メタデータは、ローカルに保存されたファイルからのみ事前に読み込むことができます)。

  2. NetConnection オブジェクトと NetStream オブジェクトを作成して、NetStream クライアントオブジェクトの onDRMContentData() コールバック関数および onPlayStatus() コールバック関数を実装します。

  3. NetStreamPlayOptions オブジェクトを作成し、 stream プロパティをローカルのメディアファイルの URL に設定します。

  4. NetStream preloadEmbeddedMetadata() を呼び出して、解析するメディアファイルを識別する NetStreamPlayOptions オブジェクトを渡します。

  5. メディアファイルに DRM メタデータが含まれている場合は、 onDRMContentData() コールバック関数が呼び出されます。メタデータは、この関数に DRMContentData オブジェクトとして渡されます。

  6. DRMManager loadVoucher() メソッドを使用し、DRMContentData オブジェクトを使用して証明書を取得します。

    DRMContentData オブジェクトの authenticationMethod プロパティの値が flash.net.drm.AuthenticationMethod.USERNAME_AND_PASSWORD の場合は、証明書を読み込む前に Media Rights Server でユーザーを認証する必要があります。DRMContentData オブジェクトの serverURL プロパティおよび domain プロパティが、ユーザー情報と共に DRMManager authenticate() メソッドに渡されます。

  7. ファイルの解析が完了すると、 onPlayStatus() コールバック関数が呼び出されます。 onDRMContentData() 関数が呼び出されていない場合、そのファイルには証明書の取得に必要なメタデータが含まれていません。また、この関数が呼び出されていない場合、Adobe Access がこのファイルを保護していない可能性があります。

例えば、次の AIR 用のコードは、ローカルのメディアファイルの 証明書を事前に読み込む方法を示しています。

package 
{ 
import flash.display.Sprite; 
import flash.events.DRMAuthenticationCompleteEvent; 
import flash.events.DRMAuthenticationErrorEvent; 
import flash.events.DRMErrorEvent;   
import flash.ev ents.DRMStatusEvent; 
import flash.events.NetStatusEvent; 
import flash.net.NetConnection; 
import flash.net.NetStream; 
import flash.net.NetStreamPlayOptions; 
import flash.net.drm.AuthenticationMethod; 
import flash.net.drm.DRMContentData; 
import flash.net.drm.DRMManager; 
import flash.net.drm.LoadVoucherSetting;   
public class DRMPreloader extends Sprite  
{ 
     private var videoURL:String = "app-storage:/video.flv"; 
    private var userName:String = "user"; 
    private var password:String = "password";  
    private var preloadConnection:NetConnection; 
    private var preloadStream:NetStream; 
    private var drmManager:DRMManager = DRMManager.getDRMManager(); 
    private var drmContentData:DRMContentData; 
    public function DRMPreloader():void { 
        drmManager.addEventListener( 
            DRMAuthenticationCompleteEvent.AUTHENTICATION_COMPLETE, 
            onAuthenticationComplete); 
        drmManager.addEventListener(DRMAuthenticationErrorEvent.AUTHENTICATION_ERROR, 
            onAuthenticationError);             
        drmManager.addEventListener(DRMStatusEvent.DRM_STATUS, onDRMStatus); 
        drmManager.addEventListener(DRMErrorEvent.DRM_ERROR, onDRMError); 
        preloadConnection = new NetConnection(); 
        preloadConnection.addEventListener(NetStatusEvent.NET_STATUS, onConnect); 
        preloadConnection.connect(null);            
    } 
 
    private function onConnect( event:NetStatusEvent ):void 
    { 
        preloadMetadata(); 
    } 
    private function preloadMetadata():void 
    { 
        preloadStream = new NetStream( preloadConnection ); 
        preloadStream.client = this; 
        var options:NetStreamPlayOptions = new NetStreamPlayOptions(); 
        options.streamName = videoURL; 
        preloadStream.preloadEmbeddedData( options );                         
    }     
    public function onDRMContentData( drmMetadata:DRMContentData ):void 
    { 
        drmContentData = drmMetadata; 
        if ( drmMetadata.authenticationMethod == AuthenticationMethod.USERNAME_AND_PASSWORD ) 
        { 
            authenticateUser(); 
        } 
        else 
            { 
                getVoucher(); 
            } 
    } 
    private function getVoucher():void 
    { 
        drmManager.loadVoucher( drmContentData, LoadVoucherSetting.ALLOW_SERVER ); 
    } 
 
    private function authenticateUser():void 
    { 
        drmManager.authenticate( drmContentData.serverURL, drmContentData.domain, userName, password ); 
    } 
    private function onAuthenticationError( event:DRMAuthenticationErrorEvent ):void 
    { 
        trace( "Authentication error: " + event.errorID + ", " + event.subErrorID ); 
    } 
 
    private function onAuthenticationComplete( event:DRMAuthenticationCompleteEvent ):void 
    { 
        trace( "Authenticated to: " + event.serverURL + ", domain: " + event.domain ); 
        getVoucher(); 
    } 
    private function onDRMStatus( event:DRMStatusEvent ):void 
    { 
        trace( "DRM Status: " + event.detail); 
        trace("--Voucher allows offline playback = " + event.isAvailableOffline ); 
        trace("--Voucher already cached          = " + event.isLocal ); 
        trace("--Voucher required authentication = " + !event.isAnonymous ); 
    } 
    private function onDRMError( event:DRMErrorEvent ):void 
    { 
        trace( "DRM error event: " + event.errorID + ", " + event.subErrorID + ", " + event.text ); 
    } 
    public function onPlayStatus( info:Object ):void 
    { 
        preloadStream.close(); 
    } 
} 
}