Wyjaśnienie obiegu pracy chronionych treści

Flash Player 10.1 i nowsze wersje, Adobe AIR 2.0 i nowsze wersje

Ważne : Program Flash Player 11.5 lub nowszy zapewnia integrację z modułem Adobe Access, więc etap aktualizacji — wywołanie metody SystemUpdater.update(SystemUpdaterType.DRM) — jest zbędny. Dotyczy to następujących przeglądarek i platform:

  • Formant Flash Player 11.5 ActiveX dla wszystkich platform poza programem Internet Explorer w systemie Windows 8 na komputerze z procesorem Intel

  • Wtyczka Flash Player 11.5 dla wszystkich przeglądarek

  • Środowisko Adobe AIR (komputery i urządzenia przenośne)

Etap aktualizacji jest nadal wymagany w następujących przypadkach:

  • Program Internet Explorer w systemie Windows 8 na komputerze z procesorem Intel

  • Program Flash Player 11.4 lub starszy z wyjątkiem przeglądarki Google Chrome 22 i nowszych (wszystkie platformy) lub 21 i nowszych (system Windows)

Uwaga: Wywołanie metody SystemUpdater.update(SystemUpdaterType.DRM) w systemie z programem Flash Player 11.5 lub nowszym nie ma negatywnych skutków, ale nie powoduje też pobrania jakichkolwiek danych.

Na przykładzie poniższego ogólnego obiegu pracy przedstawiono, jak aplikacja może pobierać i odtwarzać chronioną zawartość. W tym obiegu pracy przyjęto, że aplikacja jest zaprogramowana konkretnie do odtwarzania treści chronionych przez moduł Adobe Access.

  1. Pobierz metadane treści.

  2. W razie potrzeby obsłuż aktualizacje programu Flash Player.

  3. Sprawdź, czy licencja jest dostępna lokalnie. Jeżeli tak, załaduj licencję i przejdź do kroku 7. Jeżeli nie, przejdź do kroku 4.

  4. Sprawdź, czy wymagane jest uwierzytelnienie. Jeżeli nie, możesz przejść do kroku 7.

  5. Jeżeli uwierzytelnienie jest wymagane, pobierz poświadczenia uwierzytelniające użytkownika i przekaż je do serwera licencji.

  6. Jeśli jest wymagana rejestracja w domenie, przyłącz się do domeny (w środowisku AIR 3.0 lub nowszym).

  7. Po pomyślnym przeprowadzeniu uwierzytelnienia pobierz licencję z serwera.

  8. Odtwórz treści.

Jeśli nie wystąpił błąd i pomyślnie zweryfikowano uprawnienia użytkownika do wyświetlenia treści, obiekt NetStream wywołuje obiekt DRMStatusEvent. Aplikacja rozpoczyna wówczas odtwarzanie. Obiekt DRMStatusEvent zawiera pokrewne informacje z kuponu, które identyfikują zasady i uprawnienia użytkownika. Zawiera on, na przykład, informacje o tym, czy treści można udostępniać offline lub o tym, kiedy kończy się ważność licencji. Aplikacja na podstawie tych danych może poinformować użytkownika o obowiązujących go zasadach. Na przykład aplikacja może na pasku stanu wyświetlić pozostałą liczbę dni, przez jaką użytkownik będzie jeszcze mieć uprawnienia do wyświetlania treści.

Jeżeli użytkownikowi zostanie przyznany dostęp w trybie offline, kupon zostanie umieszczony w buforze, a zaszyfrowana zawartość zostanie pobrana na komputer użytkownika. Zawartość jest udostępniana na czas zdefiniowany przez właściwość czasu buforowania licencji. Właściwość detail obiektu zdarzenia zawiera tekst „DRM.voucherObtained". Aplikacja decyduje o miejscu lokalnego przechowywania treści udostępnianej w trybie offline. Można także wstępnie załadować kupony, korzystając z klasy DRMManager.

Uwaga: Buforowanie i wstępne wczytywanie kuponów jest obsługiwane zarówno w środowisku AIR, jak i w programie Flash Player. Tylko środowisko AIR obsługuje pobieranie i przechowywanie zawartości zaszyfrowanej.

Do aplikacji należy jawne obsługiwanie zdarzeń błędów. Dotyczy to przypadków, w których użytkownik wprowadza poprawne poświadczenia, ale kupon chroniący zaszyfrowaną treść ogranicza dostęp do niej. Na przykład, uwierzytelniony użytkownik nie może uzyskać dostępu do treści, jeżeli nie uiszczono opłaty za uprawnienia do korzystania z nich. Taka sytuacja może również wystąpić, gdy dwóch zarejestrowanych abonentów tego samego wydawcy próbuje udostępnić treść, za którą zapłacił tylko jeden z nich. Aplikacja musi informować użytkownika o błędach i proponować alternatywne rozwiązania. Typowym alternatywnym rozwiązaniem jest wyświetlenie instrukcji rejestracji i opłacenia praw do wyświetlania.

Szczegółowy obieg pracy API

W tym obiegu pracy przedstawiono bardziej szczegółowy widok obiegu pracy treści chronionych. W tym obiegu pracy opisano konkretne interfejsy API służące do odtwarzania treści chronionych przez moduł Adobe Access.

  1. Za pomocą obiektu URLLoader załaduj bajty pliku metadanych chronionych treści. Ustaw ten obiekt jako zmienną, np. metadata_bytes .

    Wszystkie treści sterowane przez moduł Adobe Access zawierają metadane tego modułu. Po spakowaniu treści te metadane można zapisać jako oddzielny plik metadanych (METADATA) obok treści. Więcej informacji znajduje się w dokumentacji modułu Adobe Access.

  2. Utwórz instancję DRMContentData. Umieść ten kod w bloku try-catch:

    new DRMContentData( metadata_bytes )

    gdzie metadata_bytes to obiekt URLLoader uzyskany w kroku 1.

  3. (Dotyczy tylko programu Flash Player) Środowisko wykonawcze szuka modułu Adobe Access. Jeśli moduł nie zostanie znaleziony, zostanie wygenerowany wyjątek IllegalOperationError ze zdarzeniem DRMErrorEvent zawierającym kod błędu 3344 lub zdarzeniem DRMErrorEvent z kodem błędu 3343.

    Aby obsłużyć ten błąd, należy pobrać moduł Adobe Access, korzystając z interfejsu API klasy SystemUpdater. Po pobraniu modułu obiekt SystemUpdater wywołuje zdarzenie COMPLETE. Dołącz detektor zdarzeń dla tego zdarzenia, który spowoduje powrót do kroku 2 po wywołaniu tego zdarzenia. Poniższy kod ilustruje opisane wyżej kroki:

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

    Jeżeli wymagana jest aktualizacja samego odtwarzacza, wywołane zostanie zdarzenie status. Więcej informacji na temat obsługi tego zdarzenia zawiera sekcja Wykrywanie zdarzenia update .

    Uwaga: W aplikacjach środowiska AIR instalator AIR obsługuje aktualizacje modułu Adobe Access i wymagane aktualizacje środowiska wykonawczego.
  4. Utwórz detektory do nasłuchiwania zdarzeń DRMStatusEvent i DRMErrorEvent wywoływanych z obiektu DRMManager:

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

    W detektorze DRMStatusEvent sprawdź ważność kuponu (wartość inna niż null). W detektorze DRMErrorEvent obsłuż zdarzenia DRMErrorEvent. Patrz sekcje Korzystanie z klasy DRMStatusEvent oraz Korzystanie z klasy DRMErrorEvent .

  5. Załaduj kupon (licencję) wymagany do odtworzenia treści.

    Najpierw spróbuj załadować lokalnie zapisaną licencję do odtwarzania treści:

    DRMManager.loadvoucher(drmContentData, LoadVoucherSetting.LOCAL_ONLY)

    Po zakończeniu ładowania obiekt DRMManager wywołuje zdarzenie DRMStatusEvent.DRM_Status .

  6. Jeżeli obiekt DRMVoucher ma wartość inną niż null, kupon jest ważny. Przejdź do kroku 13.

  7. Jeżeli obiekt DRMVoucher ma wartość null, sprawdź metodę uwierzytelniania wymaganą przez strategię dla tych treści. Użyj właściwości DRMContentData.authenticationMethod .

  8. Jeżeli metodą uwierzytelniania jest metoda ANONYMOUS , przejdź do kroku 13.

  9. Jeżeli metodą uwierzytelniania jest metoda USERNAME_AND_PASSWORD , aplikacja użytkownika musi udostępnić mechanizm umożliwiający użytkownikowi wprowadzenie poświadczeń. Przekaż te poświadczenia do serwera licencji w celu uwierzytelnienia użytkownika.

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

    Obiekt DRMManager wywołuje zdarzenie DRMAuthenticationErrorEvent , jeśli uwierzytelnienie nie powiedzie się lub zdarzenie DRMAuthenticationCompleteEvent , jeżeli uwierzytelnienie zakończy się powodzeniem. Utwórz detektory dla tych zdarzeń.

  10. Jeśli metoda uwierzytelniania ma wartość UNKNOWN (nieznana), należy zastosować własną metodę uwierzytelniania. W takiej sytuacji dostawca zawartości przygotowuje architekturę uwierzytelniania poza środowiskiem — nieużywającą interfejsów API języka ActionScript 3.0. Własna procedura uwierzytelniania musi tworzyć token uwierzytelniania, który można przekazać do metody DRMManager.setAuthenticationToken() .

  11. Jeżeli uwierzytelnienie nie powiedzie się, aplikacja musi powrócić do kroku 9. Upewnij się, że aplikacja, której używasz zawiera mechanizm do obsługi i ograniczania powtarzanych błędów uwierzytelniania. Na przykład po trzech próbach użytkownikowi wyświetlany jest komunikat informujący o nieudanym uwierzytelnieniu i braku możliwości odtworzenia treści.

  12. Aby korzystać z zapisanego tokenu zamiast wymagać od użytkownika wprowadzania poświadczeń, ustaw token za pomocą metody DRMManager.setAuthenticationToken() . Następnie pobierz licencję z serwera licencji i odtwórz treści tak, jak to opisano w kroku 8.

  13. (Opcjonalne) Jeżeli uwierzytelnienie zakończy się powodzeniem, można przechwycić token uwierzytelnienia, który jest tablicą bajtową zapisaną w pamięci podręcznej. Token ten można uzyskać za pomocą właściwości DRMAuthenticationCompleteEvent.token . Token uwierzytelniania można również zapisać i wykorzystywać później, aby użytkownik nie musiał wielokrotnie wprowadzać poświadczeń dla tych treści. Serwer licencji określa okres ważności dla tokenu uwierzytelniania.

  14. Jeżeli uwierzytelnienie zostanie przeprowadzone pomyślnie, pobierz licencję z serwera licencji:

    DRMManager.loadvoucher(drmContentData, LoadVoucherSetting.FORCE_REFRESH)

    Po zakończeniu ładowania obiekt DRMManager wywołuje zdarzenie DRMStatusEvent.DRM_STATUS. Należy nasłuchiwać tego zdarzenia i po jego wywołaniu można odtworzyć treści.

  15. Odtwórz wideo, tworząc obiekt NetStream i wywołując jego metodę 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); 

Obiekty DRMContentData i obiekty sesji

Po utworzeniu obiektu DRMContentData jest on używany jako obiekt sesji odnoszący się do modułu zarządzania prawami cyfrowymi (DRM, digital rights management) programu Flash Player. Wszystkie interfejsy API klasy DRMManager , które otrzymają ten obiekt DRMContentData , będą używać określonego modułu DRM. Dwa interfejsy API klasy DRMManager nie używają obiektu DRMContentData . Są to następujące metody:
  1. authenticate()

  2. setAuthenticationToken()

Ze względu na brak skojarzonego obiektu DRMContentData wywołania tych interfejsów API klasy DRMManager powodują użycie najnowszego modułu DRM znajdującego się na dysku. Może to być problematyczne, jeśli w trakcie obiegu pracy DRM aplikacji nastąpi aktualizacja modułu DRM. Rozważmy następujący scenariusz:
  1. Aplikacja tworzy obiekt DRMContentData o nazwie dane_zawartosci_1 , w którym jest stosowany moduł DRM AdobeCP1 .

  2. Aplikacja wywołuje metodę DRMManager.authenticate(dane_zawartosci_1.adres_URL_serwera,...) .

  3. Aplikacja wywołuje metodę DRMManager.loadVoucher(dane_zawartosci_1, ...) .

Jeśli moduł DRM zostanie zaktualizowany, zanim aplikacja rozpocznie krok 2, to metoda DRMManager.authenticate() wykona uwierzytelnianie przy użyciu modułu DRM AdobeCP2 . Wywołanie metody loadVoucher() w kroku 3 zakończy się niepowodzeniem, ponieważ będzie w niej nadal używany moduł DRM AdobeCP1 . Aktualizację modułu DRM mogła wywołać wcześniej inna aplikacja. Takiej sytuacji można uniknąć, wywołując aktualizację modułu DRM podczas uruchamiania aplikacji.

Zdarzenia powiązane z mechanizmem DRM

Środowisko wykonawcze wywołuje wiele zdarzeń, gdy aplikacja podejmuje próbę odtworzenia chronionych treści:

  • DRMDeviceGroupErrorEvent (tylko środowisko AIR), wywoływane przez obiekt DRMManager

  • DRMAuthenticateEvent (dotyczy tylko AIR), wywoływane przez NetStream

  • DRMAuthenticationCompleteEvent, wywoływane przez DRMManager

  • DRMAuthenticationErrorEvent, wywoływane przez DRMManager

  • DRMErrorEvent, wywoływane przez NetStream i DRMManager

  • DRMStatusEvent, wywoływane przez NetStream i DRMManager

  • StatusEvent

  • NetStatusEvent. Patrz sekcja Wykrywanie zdarzenia update .

W celu obsłużenia treści chronionych przez moduł Adobe Access należy dodać detektory zdarzeń obsługujące zdarzenia mechanizmu DRM.

Wstępne wczytywanie kuponów w celu odtwarzania offline

Możliwe jest wstępne wczytanie kuponów (licencji) wymaganych do odtwarzania treści chronionych przez moduł Adobe Access. Wstępnie wczytane kupony umożliwiają użytkownikom wyświetlanie zawartości niezależnie do tego, czy w danej chwili mają aktywne połączenie z Internetem. (Do samego wstępnego załadowania kuponu połączenie z Internetem jest wymagane). Do wstępnego ładowania kuponów służy metoda preloadEmbeddedMetadata() klasy NetStream oraz klasa DRMManager środowiska. W wersji środowiska AIR 2.0 i nowszych można użyć obiektu DRMContentData do bezpośredniego wstępnego załadowania kuponów. Jest to preferowana technika, gdyż umożliwia zaktualizowanie obiektu DRMContentData niezależnie od treści. (Metoda preloadEmbeddedData() pobiera obiekt DRMContentData z treści.)

Korzystanie z obiektu DRMContentData

W poniższej procedurze przedstawiono obieg pracy wstępnego wczytywania kuponu dla chronionego pliku multimedialnego za pomocą obiektu DRMContentData.

  1. Pobierz binarne metadane dla spakowanych treści. W przypadku korzystania z programu Adobe Access Java Reference Packager ten plik zostanie automatycznie wygenerowany z rozszerzeniem METADATA . Metadane można np. pobrać za pomocą klasy URLLoader.

  2. Utwórz obiekt DRMContentData, przekazując metadane do konstruktora:

    var drmData:DRMContentData = new DRMContentData( metadata );
  3. Pozostałe kroki są takie same, jak te przedstawione w obiegu pracy opisanym w części Wyjaśnienie obiegu pracy chronionych treści .

Korzystanie z obiektu preloadEmbeddedMetadata()

Poniżej przedstawiono kolejne etapy procedury wstępnego wczytywania kuponu dla pliku multimedialnego chronionego mechanizmem DRM za pomocą metody preloadEmbeddedMetadata() .

  1. Pobierz i zachowaj plik multimedialny. (Metadane DRM można wstępnie wczytywać wyłącznie z plików zapisanych lokalnie).

  2. Utwórz obiekty NetConnection i NetStream, tworząc implementacje funkcji wywołania zwrotnego onDRMContentData() i onPlayStatus() w obiekcie klienckim NetStream.

  3. Utwórz obiekt NetStreamPlayOptions i przypisz właściwości stream adres URL lokalnego pliku multimedialnego.

  4. Wywołaj metodę preloadEmbeddedMetadata() obiektu NetStream, przekazując do niej obiekt NetStreamPlayOptions wskazujący plik multimedialny do przeanalizowania.

  5. Jeśli plik multimedialny zawiera metadane DRM, wywoływana jest funkcja wywołania zwrotnego onDRMContentData() . Metadane są przekazywane do tej funkcji jako obiekt DRMContentData.

  6. Użyj obiektu DRMContentData do uzyskania kuponu, korzystając z metody loadVoucher() klasy DRMManager.

    Jeśli właściwość authenticationMethod obiektu DRMContentData ma wartość flash.net.drm.AuthenticationMethod.USERNAME_AND_PASSWORD , należy uwierzytelnić użytkownika na serwerze zarządzania prawami do multimediów przed wczytaniem kuponu. Właściwości serverURL i domain obiektu DRMContentData można przekazać do metody authenticate() klasy DRMManager razem z poświadczeniami użytkownika.

  7. Po zakończeniu analizowania pliku wywoływana jest funkcja wywołania zwrotnego onPlayStatus() . Jeśli funkcja onDRMContentData() nie została wywołana, plik nie zawiera metadanych potrzebnych do uzyskania kuponu. Ten brak wywołania może także oznaczać, że moduł Adobe Access nie chroni tego pliku.

Poniższy przykładowy kod dla środowiska AIR ilustruje sposób wstępnego ładowania kuponu dla lokalnego pliku multimedialnego:

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