Förstå arbetsflödet för skyddat innehåll

Flash Player 10.1 och senare, Adobe AIR 2.0 och senare

Viktigt : I Flash Player 11.5 och senare integreras Adobe Access-modulen så uppdateringssteget (anrop av SystemUpdater.update(SystemUpdaterType.DRM) ) är inte nödvändigt. Detta gäller följande webbläsare och plattformar:

  • ActiveX-kontoll för Flash Player 11.5, för alla plattformar utom Internet Explorer i Windows 8 på Intel-processorer

  • Plugin-program för Flash Player 11.5, för alla webbläsare

  • Adobe AIR (dator och mobil)

Detta innebär att uppdateringssteget fortfarande krävs i följande fall:

  • Internet Explorer i Windows 8 på Intel-processorer

  • Flash Player 11.4 och senare, utom Google Chrome 22 och senare (alla plattformar) eller 21 och senare (Windows)

Obs! Det är fortfarande säkert att anropa SystemUpdater.update(SystemUpdaterType.DRM) i ett system med Flash Player 11.5 eller senare, men inget laddas ned.

Följande arbetsflöde på hög nivå beskriver hur ett program kan hämta och spela upp skyddat innehåll. För det här arbetsflödet förutsätts det att programmet utformas särskilt för uppspelning av innehåll som skyddas av Adobe Access:

  1. Hämta innehållets metadata.

  2. Hantera uppdateringar av Flash Player, vid behov.

  3. Kontrollera om det finns en licens lokalt tillgänglig. Om det finns en licens läser du in den och går vidare till steg 7. Om det inte gör det går du till steg 4.

  4. Kontrollera om autentisering krävs. Om det inte gör det går du vidare till steg 7.

  5. Om autentisering krävs måste inloggningsuppgifterna hämtas från användaren och skickas till licensservern.

  6. Om en domänregistrering krävs ska du gå med i domänen (AIR 3.0 och senare).

  7. När autentiseringen har slutförts kan licensen hämtas från servern.

  8. Spela upp innehållet.

Om inget fel inträffar och användaren autentiserades för att se innehållet, skickar NetStream-objektet ett DRMStatusEvent-objekt. Programmet påbörjar då uppspelningen. DRMStatusEvent-objektet innehåller relaterad voucherinformation, som identifierar användarens policy och behörigheter. Till exempel innehåller det information om innehållet kan göras tillgängligt offline eller när licensen upphör. Programmet kan använda data för att informera användaren om statusen för policyn. Programmet kan till exempel visa i statusfältet hur många dagar till som användaren kan visa innehållet.

Om användaren tillåts åtkomst offline, cache-lagras vouchern och det krypterade innehållet laddas ner till användarens dator. Innehållet är tillgängligt under den tid som angivits för licensens varaktighet i cache-minnet. Egenskapen detail i händelsen innehåller "DRM.voucherObtained" . Programmet avgör var innehållet ska sparas lokalt för att kunna visas offline. Du kan även förhandsladda en voucher med klassen DRMManager.

Obs! Cache-lagring och inläsning av vouchers i förväg stöds i både AIR och Flash Player. Hämtning och förvaring av krypterat innehåll stöds endast i AIR.

I programmet hanteras alla felhändelser explicit. Dessa händelser omfattar fall där användaren anger giltiga inloggningsuppgifter, men där åtkomsten till innehållet begränsas av vouchern som skyddar det krypterade innehållet. En autentiserad användare kan till exempel inte få åtkomst till innehållet om denne inte har betalat för rättigheterna. Detta kan också inträffa när två användare, som båda är registrerade medlemmar hos samma utgivare, försöker att dela innehåll som bara en av dem har betalat för. Programmet ska informera användaren om felet och presentera ett alternativ. Ett vanligt alternativ är att ge användaren information om hur han/hon registrerar sig och betalar för att få visa innehåll.

Utförligt API-arbetsflöde

Det här arbetsflödet ger en mer utförlig beskrivning av arbetsflödet för skyddat innehåll. Det här arbetsflödet beskriver de specifika API:er som används för att spela upp innehåll som skyddas av Adobe Access.

  1. Läs in de byte som hör till filen för det skyddade innehållets metadata med ett URLLoader-objekt. Ange en variabel för objektet, till exempel metadata_bytes .

    Allt innehåll som kontrolleras av Adobe Access har Adobe Access-metadata. När innehållet packas kan dessa metadata sparas som en separat metadata-fil (.metadata) tillsammans med innehållet. Mer information finns i dokumentationen för Adobe Access.

  2. Skapa en DRMContentData-instans. Lägg den här koden i ett try-catch-block:

    new DRMContentData( metadata_bytes )

    där metadata_bytes är URLLoader-objektet som fås i steg 1.

  3. (Endast Flash Player) Körningen kontrollerar att Adobe Access-modulen finns. Om den inte hittas inträffar ett IllegalOperationError-fel med felkoden 3344 eller 3343 för DRMErrorEvent.

    Du hantera felet genom att hämta Adobe Access-modulen med API:n SystemUpdater. När modulen har hämtats skickar SystemUpdater-objektet en COMPLETE-händelse. Inkludera en händelseavlyssnare för den här händelsen som går tillbaka till steg 2 när händelsen skickas. Följande kod visar de här stegen:

    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); 
    } 

    Om själva spelaren måste uppdateras skickas en status-händelse. Mer information om hur du hanterar den här händelsen finns i Lyssna efter en uppdateringshändelse .

    Obs! I AIR-program hanterar AIR-installationsprogrammet uppdateringen av Adobe Access-modulen och de uppdateringar av körningsversionen som behövs.
  4. Skapa avlyssnare som lyssnar efter DRMStatusEvent och DRMErrorEvent som skickas från DRMManager-objektet:

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

    Kontrollera att vouchern är giltig (inte null) i DRMStatusEvent-avlyssnaren. Hantera DRMErrorEvents i DRMErrorEvent-avlyssnaren. Se Använda klassen DRMStatusEvent och Använda klassen DRMErrorEvent .

  5. Läs in vouchern (licensen) som krävs för uppspelning av innehållet.

    Försök först att läsa in en lokalt sparad licens för att spela upp innehållet:

    DRMManager.loadvoucher(drmContentData, LoadVoucherSetting.LOCAL_ONLY)

    När inläsningen är slutförd skickar DRMManager-objektet DRMStatusEvent.DRM_Status .

  6. Om DRMVoucher-objektet inte är null är vouchern giltig. Gå till steg 13.

  7. Om DRMVoucher-objektet är null kontrollerar du autentiseringsmetoden som krävs av innehållets policy. Använd egenskapen DRMContentData.authenticationMethod .

  8. Om autentiseringsmetoden är ANONYMOUS går du vidare till steg 13.

  9. Om autentiseringsmetoden är USERNAME_AND_PASSWORD måste programmet kunna tillhandahålla en funktion som låter användaren ange inloggningsuppgifter. Skicka dessa inloggningsuppgifter till licensservern för autentisering av användaren:

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

    DRMManager skickar en DRMAuthenticationErrorEvent om autentiseringen misslyckas eller en DRMAuthenticationCompleteEvent om autentiseringen lyckas. Skapa avlyssnare för dessa händelser.

  10. Om autentiseringsmetoden är UNKNOWN , måste en egen autentiseringsmetod användas. I detta fall har innehållsleverantören ordnat så att autentiseringen görs vid sidan om utan hjälp av ActionScript 3.0-API:er. Den egna autentiseringsproceduren måste skapa en autentiseringstoken som kan skickas till metoden DRMManager.setAuthenticationToken() .

  11. Om autentiseringen misslyckas måste programmet återgå till steg 9. Kontrollera att programmet har en funktion för att hantera och begränsa upprepade autentiseringsförsök. Det kan till exempel vara ett meddelande som visas efter tre misslyckade försök och som anger att autentiseringen misslyckades och att innehållet inte kan spelas upp.

  12. Om du vill använda en lagrad token istället för att fråga användaren om inloggningsuppgifter anger du en token med metoden DRMManager.setAuthenticationToken() . Hämta sedan licensen från licensservern och spela upp innehållet som i steg 8.

  13. (Valfritt) Om autentiseringen lyckas kan du hämta in en autentiseringstoken, vilket utgörs av en cachelagrad bytearray i minnet. Hämta denna token med egenskapen DRMAuthenticationCompleteEvent.token . Det går att lagra och använda en autentiseringstoken så att användaren inte behöver ange sina inloggningsuppgifter flera gånger för samma innehåll. Licensservern avgör giltighetsperioden för denna autentiseringstoken.

  14. Om autentiseringen lyckas hämtas licensen från servern.

    DRMManager.loadvoucher(drmContentData, LoadVoucherSetting.FORCE_REFRESH)

    När inläsningen är slutförd skickar DRMManager-objektet DRMStatusEvent.DRM_STATUS. Lyssna efter den här händelsen, när den skickas går det att spela upp innehållet.

  15. Spela upp videofilmen genom att skapa ett NetStream-objekt och anropa sedan dess play() -metod:

    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 och sessionsobjekt

När DRMContentData skapas kommer det att används som ett sessionsobjekt som refererar till Flash Players DRM-modul. Alla DRMManager -API:er som tar emot detta DRMContentData kommer att använda den speciella DRM-modulen. Det finns emellertid två 2 DRMManager -API:er som inte använder DRMContentData . De är:
  1. authenticate()

  2. setAuthenticationToken()

Eftersom det inte finns några associerade DRMContentData , kommer anrop av dessa DRMManager -API:er att innebära att den senaste DRM-modulen från disken används. Detta kan innebära ett problem om en uppdatering av DRM-modulen inträffar under programmets DRM-arbetsflöde. Tänk dig följande scenario:
  1. Programmet skapar ett DRMContentData -objekt contentData1 , som använder AdobeCP1 som en DRM-modul.

  2. Programmet anropar metoden DRMManager.authenticate(contentData1.serverURL,...) .

  3. Programmet anropar metoden DRMManager.loadVoucher(contentData1, ...) .

Om en uppdatering för DRM-modulen inträffar innan programmet kan komma till steg 2, kommer metoden DRMManager.authenticate() att avsluta autentiseringen med AdobeCP2 som DRM-modul. Metoden loadVoucher() i steg 3 kommer att misslyckas eftersom AdobeCP1 fortfarande används som DRM-modul. Uppdateringen kan ha inträffat på grund av att ett annat program anropar DRM-moduluppdateringen. Du kan undvika detta scenario genom att anropa DRM-moduluppdateringen när programmet startas.

DRM-relaterade händelser

I körningen skickas flera händelser när ett program försöker att spela upp skyddat innehåll:

  • DRMDeviceGroupErrorEvent (endast AIR), skickas av DRMManager

  • DRMAuthenticateEvent (endast AIR), skickas av NetStream

  • DRMAuthenticationCompleteEvent, skickas av DRMManager

  • DRMAuthenticationErrorEvent, skickas av DRMManager

  • DRMErrorEvent, skickas av NetStream och DRMManager

  • DRMStatusEvent, skickas av NetStream och DRMManager

  • StatusEvent

  • NetStatusEvent. Se Lyssna efter en uppdateringshändelse

Om du vill ha stöd för innehåll skyddat av Adobe Access lägger du till händelseavlyssnare för hantering av DRM-händelserna.

Läs in vouchers i förväg för uppspelning offline

Du kan i förväg ladda vouchers (licenser) som krävs för uppspelning av innehåll som skyddas av Adobe Access. Med en förinläst voucher kan användarna visa innehållet även om de inte har en aktiv internetanslutning. (För själva förladdningen krävs dock en Internetanslutning.) Du kan använda metoden preloadEmbeddedMetadata() i NetStream-klassen och DRMManager-klassen för att ladda en voucher i förväg. I AIR 2.0 och senare kan du använda ett DRMContentData-objekt om du vill ladda en voucher. Den här metoden är att föredra eftersom den låter dig uppdatera DRMContentData-objektet oberoende av innehållet. (Metoden preloadEmbeddedData() hämtar DRMContentData från innehållet.)

Använda DRMContentData

Följande steg beskriver hur du läser in vouchern för en skyddad mediefil i förväg med ett DRMContentData-objekt.

  1. Hämta binära metadata för det packade innehållet. Om du använder referenspaketeraren för Java i Adobe Access genereras denna metadatafil automatiskt med filtillägget .metadata . Du skulle till exempel kunna hämta dessa metadata med klassen URLLoader.

  2. Skapa ett DRMContentData-objekt och skicka metadata till konstruktorfunktionen:

    var drmData:DRMContentData = new DRMContentData( metadata );
  3. Resten av stegen är identiska med arbetsflödet som beskrivs i Förstå arbetsflödet för skyddat innehåll .

Använda preloadEmbeddedMetadata()

I följande steg beskrivs hur du läser in vouchern i förväg med preloadEmbeddedMetadata() för en DRM-skyddad mediefil:

  1. Hämta och lagra mediefilen. (DRM-metadata kan bara läsas in i förväg från filer som är lagrade på lokalt.)

  2. Skapa objekten NetConnection och NetStream, och ange implementeringar för callback-funktionerna onDRMContentData() och onPlayStatus() för NetStream client-objektet.

  3. Skapa ett NetStreamPlayOptions-objekt och associera egenskapen stream med den lokala mediefilens URL.

  4. Anropa preloadEmbeddedMetadata() -metoden i NetStream-klassen och ange NetStreamPlayOptions-objektet som identifierar den mediefil som ska tolkas.

  5. Om mediefilen innehåller DRM-metadata anropas callback-funktionen onDRMContentData() . Metadata skickas till den här funktionen som ett DRMContentData-objekt.

  6. Använd objektet DRMContentData för att erhålla vouchern med hjälp av loadVoucher() -metoden för DRMManager-objektet.

    Om egenskapen authenticationMethod för objektet DRMContentData har värdet flash.net.drm.AuthenticationMethod.USERNAME_AND_PASSWORD autentiserar du användaren på medierättighetsservern innan vouchern läses in. Egenskaperna serverURL och domain i DRMContentData-objektet kan överföras till authenticate() -metoden i DRMManager, tillsammans med användarens autentiseringsuppgifter.

  7. Callback-funktionen onPlayStatus() anropas när filtolkningen är slutförd. Om onDRMContentData() -funktionen inte har anropats innehåller filen inte de metadata som krävs för att få en voucher. Det saknade anropet kan också medföra att Adobe Access inte skyddar den här filen.

Följande kodexempel för AIR illustrerar hur du läser in en voucher för en lokal mediefil i förväg:

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(); 
    } 
} 
}