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

Flash Player 10.1 以降、Adobe AIR 2.0 以降

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

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

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

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

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

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

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

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

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

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

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

詳細な API ワークフロー

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

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

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

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

    new DRMContentData(metadata_bytes)

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

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

    このエラーを処理するには、SystemUpdater API を使用して Flash 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 インストーラーは Flash 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. 認証が失敗した場合、アプリケーションは手順 9 に戻る必要があります。アプリケーションに、認証の失敗が繰り返されたときにそれを処理し、制限するメカニズムがあることを確認します。例えば、3 回の試行後に、認証に失敗してコンテンツを表示できないことを示すメッセージをユーザーに表示します。

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

    DRMManager.loadvoucher(drmContentData, LoadVoucherSetting.FORCE_REFRESH)

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

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

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

  13. 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); 

DRM 関連イベント

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

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

  • DRMAuthenticationCompleteEvent、DRMManager によって送出

  • DRMAuthenticationErrorEvent、DRMManager によって送出

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

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

  • StatusEvent

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

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

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

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

DRMContentData の使用

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

  1. パッケージ化されたコンテンツのバイナリメタデータを取得します。Flash 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 プロパティの値が userNameAndPassword の場合は、証明書を読み込む前に Media Rights Server でユーザーを認証する必要があります。DRMContentData オブジェクトの serverURL プロパティおよび domain プロパティが、ユーザー情報と共に DRMManager authenticate() メソッドに渡されます。

  7. ファイルの解析が完了すると、onPlayStatus() コールバック関数が呼び出されます。onDRMContentData() 関数が呼び出されていない場合、そのファイルには証明書の取得に必要なメタデータが含まれていません。また、この関数が呼び出されていない場合、Flash 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(); 
    } 
} 
}