Entendendo o fluxo de trabalho de conteúdo protegido.

Flash Player 10.1 e posterior, Adobe AIR 2.0 e posterior

Importante : o Flash Player 11.5 e superior integram o módulo do Adobe Access, portanto, a etapa de atualização (chamar SystemUpdater.update(SystemUpdaterType.DRM) ) é desnecessária. Isso inclui os seguintes navegadores e plataformas:

  • Controle ActiveX do Flash Player 11.5, para todas as plataformas exceto o Internet Explorer no Windows 8 em processadores Intel

  • Plug-in do Flash Player 11.5, para todos os navegadores

  • Adobe AIR (desktop e dispositivos móveis)

Isso significa que a etapa de atualização é necessária nos seguintes casos:

  • Internet Explorer no Windows 8 em processadores Intel

  • Flash Player 11.4 e inferior, exceto no Chrome 22 e superior (todas as plataformas) ou 21 e superior (Windows)

Nota: Ainda é possível chamar SystemUpdater.update(SystemUpdaterType.DRM) com segurança em um sistema com Flash Player 11.5 ou superior, mas nenhum item será baixado.

O seguinte fluxo de trabalho mostra como um aplicativo pode salvar e executar o conteúdo protegido. O fluxo de trabalho pressupõe que o aplicativo é projetado para reproduzir especificamente conteúdo protegido pelo Adobe Access:

  1. Obtenha os metadados do conteúdo.

  2. Trata das atualizações do Flash Player, se necessário.

  3. Verifique se uma licença está disponível localmente. Se sim, carregue-o e siga para o passo 7. Se não, vá para o passo 4.

  4. Verifique se a autenticação é necessária. Se não, vá para o passo 7.

  5. Caso a autenticação seja necessária, obtenha as credenciais de autenticação para o usuário e passe-as para o servidor de licenças.

  6. Caso seja necessário o registro de domínio, cadastre-se no domínio (AIR 3.0 e superior).

  7. Uma vez que a autenticação aconteça, baixe a licença do servidor.

  8. Reproduza o conteúdo.

Se não tiver ocorrido nenhum erro e o usuário foi autorizado com êxito a exibir o conteúdo, o objeto NetStream enviará um objeto DRMStatusEvent. O aplicativo inicia a reprodução. O objeto DRMStatusEvent guarda as informações de voucher relacionadas, que identificam a política e as permissões do usuário. Por exemplo, ele possui informações sobre se o conteúdo pode ser disponibilizado offline ou quando a licença expira. O aplicativo pode usar esses dados para informar ao usuário sobre o status de sua política. Por exemplo, o aplicativo pode exibir o número de dias restantes que o usuário possui para exibir o conteúdo em uma barra de status.

Caso o usuário tenha permissão para o acesso offline, o voucher será armazenado em cache e o conteúdo criptografado será transferido para o computador do usuário. O conteúdo torna-se acessível para a duração definida na duração do armazenamento em cache da licença. A propriedade detail no evento contém "DRM.voucherObtained" . O aplicativo decide onde armazenar o conteúdo localmente para que ele esteja disponível offline. Você também pode pré-carregar vouchers usando a classe DRMManager.

Nota: O armazenamento em cache e o pré-carregamento dos vouchers é suportado no AIR e no Flash Player. No entanto, o download e o armazenamento de conteúdo criptografado são suportados somente no AIR.

É de responsabilidade do aplicativo lidar especificamente com as ocorrências de erros. Estes eventos incluem casos nos quais o usuário insere credenciais válidas, mas o voucher que protege o conteúdo criptografado restringe o acesso ao conteúdo. Por exemplo, um usuário autenticado não pode acessar o conteúdo se os direitos não estiverem pagos. Este caso também pode ocorrer quando dois integrantes registrados do mesmo provedor tentar compartilhar conteúdo adquirido somente por um deles. O aplicativo deve informar o usuário do erro e oferecer uma sugestão alternativa. Uma sugestão alternativa comum são as instruções sobre como registrar e pagar por direitos de visualização.

Fluxo de trabalho detalhado

Este fluxo de trabalho fornece uma visão mais detalhada do fluxo de trabalho do conteúdo protegido. Esse fluxo de trabalho descreve as APIs especificas utilizadas para reproduzir conteúdo protegido pelo Adobe Access.

  1. Utilizando um objeto URLLoader, carregue os bytes do arquivo de metadados do conteúdo protegido. Defina este objeto para uma variável como metadata_bytes .

    Todo o conteúdo controlado pelo Adobe Access possui metadados do Adobe Access. Quando o conteúdo é empacotado, esses metadados podem ser salvos como um arquivo metadados separado (.metadata) junto com o conteúdo. Para obter mais informações, consulte a documentação do Adobe Access.

  2. Crie uma ocorrência de DRMContentData. Coloque este código em um bloco try-catch:

    new DRMContentData( metadata_bytes )

    onde metadata_bytes é o objeto URLLoader obtido no passo 1.

  3. (Apenas para o Flash Player) O runtime faz uma verificação sobre o módulo do Adobe Access. Caso não seja encontrado, um código de erro IllegalOperationError 3344 ou um código de erro DRMErrorEvent 3343 será lançado.

    Para tratar desse erro, faça o download do módulo Adobe Access utilizando a API SystemUpdater. Depois que o módulo for baixado, os objeto SystemUpdater envia um evento COMPLETE. Inclua um ouvinte de eventos para este evento que volta para o passo 2 quando este evento é enviado. O código a seguir demonstra as etapas:

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

    Se o próprio player precisa ser atualizado, um evento de status é enviado. Para mais informações sobre como manipular este evento, veja Procurando um evento de atualização .

    Nota: Nos aplicativos AIR, o instalador AIR manipula a atualização do módulo do Adobe Access e de atualizações do runtime necessárias.
  4. Crie ouvintes para ouvir os eventos DRMStatusEvent e DRMErrorEvent enviados do objeto DRMManager:

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

    No ouvinte DRMStatusEvent, verifique se o voucher é válido (não null). No ouvinte DRMErrorEvent, manipule DRMErrorEvents. Veja Uso da classe DRMStatusEvent e Uso da classe DRMErrorEvent .

  5. Carregue o voucher (licença) necessário para reproduzir o conteúdo.

    Primeiro, tente carregar uma licença armazenada localmente para reproduzir o conteúdo:

    DRMManager.loadvoucher(drmContentData, LoadVoucherSetting.LOCAL_ONLY)

    Depois que o carregamento estiver completo o objeto DRMManager envia DRMStatusEvent.DRM_Status .

  6. Caso o objeto DRMVoucher não seja null, o voucher é válido. Avançar para a etapa 13.

  7. Caso o objeto DRMVoucher seja null, verifique o método de autenticação necessário pela política para este conteúdo. Utilize a propriedade DRMContentData.authenticationMethod .

  8. Caso o método de autenticação seja ANONYMOUS , vá para o passo 13.

  9. Caso o método de autenticação seja USERNAME_AND_PASSWORD , seu aplicativo precisa fornecer um mecanismo para que o usuário insira as credenciais. Passe estas credenciais para o servidor de licenças para autenticar o usuário:

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

    O DRMManager envia um DRMAuthenticationErrorEvent caso a autenticação falhe ou um DRMAuthenticationCompleteEvent caso a autenticação funcione. Crie ouvintes para estes eventos.

  10. Se o método de autenticação for UNKNOWN , um método padrão de autenticação deverá ser usado. Nesse caso, o fornecedor de conteúdo determinou que a autenticação fosse feita no modo fora de banda não usando as APIs do ActionScript 3.0. O procedimento para a autenticação padrão deve produzir um testemunho de autenticação que pode ser transmitido para o método DRMManager.setAuthenticationToken() .

  11. Caso a autenticação falhe, seu aplicativo deve retornar para o passo 9. Certifique-se de que seu aplicativo tenha um mecanismo para manipular e limitar falhas de autenticação repetidas. Por exemplo, depois de três tentativas, mostre uma mensagem para o usuário indicando que a autenticação falhou e que o conteúdo não pode ser reproduzido.

  12. Para utilizar o token armazenado em vez de solicitar que o usuário insira as credenciais, defina o token com o método DRMManager.setAuthenticationToken() . Então você pode baixar a licença do servidor de licenças e reproduzir o conteúdo como no passo 8.

  13. (opcional) Caso a autenticação proceda, você pode capturar o token de autenticação, que é uma matriz de bytes armazenada na memória. Capture este token com a propriedade DRMAuthenticationCompleteEvent.token . Você pode armazenar e utilizar o token de autenticação para que o usuário não precise inserir as credenciais repetidamente para este conteúdo. O servidor de licença determina o período de validade do token de autenticação.

  14. Caso a autenticação aconteça, baixe a licença do servidor de licenças.

    DRMManager.loadvoucher(drmContentData, LoadVoucherSetting.FORCE_REFRESH)

    Depois que o carregamento estiver completo o objeto DRMManager envia DRMStatusEvent.DRMStatus Ouça este evento e quando ele for enviado, o conteúdo pode ser reproduzido.

  15. Reproduzir o vídeo criando um objeto NetStream e chamando o método 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 e objetos da sessão

Quando os DRMContentData são criados, eles são usados como objetos da sessão que se referem ao módulo do Flash Player do DRM. Todas as APIs DRMManager que recebem esses DRMContentData usarão aquele módulo DRM específico. No entanto, existem 2 APIs DRMManager que não utilizam DRMContentData . São as seguintes:
  1. authenticate()

  2. setAuthenticationToken()

Uma vez que não há DRMContentData associados, a execução dessas APIs DRMManager utilizará o último módulo DRM do disco. Isso poderá se tornar um problema caso ocorra uma atualização no módulo DRM no meio do fluxo de trabalho do DRM do aplicativo. Considere a seguinte situação:
  1. O aplicativo cria um objeto DRMContentData contentData1 , que usa o AdobeCP1 como o módulo DRM.

  2. O aplicativo executa o método DRMManager.authenticate(contentData1.serverURL,...) .

  3. O aplicativo executa o método DRMManager.loadVoucher(contentData1, ...) .

Caso ocorra uma atualização no módulo DRM antes que o aplicativo consiga chegar à etapa 2, então o método DRMManager.authenticate() finalizará a autenticação usando o AdobeCP2 como o módulo DRM. O método loadVoucher() na etapa 3 falhará, uma vez que ele ainda utiliza o AdobeCP1 como o módulo DRM. A atualização pode ter ocorrido devido a um outro aplicativo que executa a atualização do módulo DRM. É possível evitar essa situação executando a atualização do módulo DRM na inicialização do aplicativo.

Eventos relacionados ao DRM

O tempo de execução envia vários eventos quando um aplicativo tenta reproduzir conteúdo protegido:

  • DRMDeviceGroupErrorEvent (somente no AIR), encaminhado pelo DRMManager

  • DRMAuthenticateEvent (apenas no AIR), enviado pelo NetStream

  • DRMAuthenticationCompleteEvent, enviado pelo DRMManager

  • DRMAuthenticationErrorEvent, enviado pelo DRMManager

  • DRMErrorEvent, enviado pelo NetStream e pelo DRMManager

  • DRMStatusEvent, enviado pelo NetStream e pelo DRMManager

  • StatusEvent

  • NetStatusEvent. Veja Procurando um evento de atualização

Para oferecer suporte a conteúdo protegido pelo Adobe Access, adicione ouvintes de eventos para manipular eventos de DRM.

Pré-carregamento de vouchers para reprodução offline

Você pode pré-carregar os vouchers (licenças) necessários para reproduzir conteúdo protegido pelo Adobe Access. Os vouchers pré-carregados permitem que os usuários visualizem o conteúdo independentemente de terem acesso à Internet. (O processo de pré-carregamento propriamente dito requer conexão com Internet.) Use o método preloadEmbeddedMetadata() da classe NetStream e a classe DRMManager do para pré-carregar vouchers. No AIR 2.0 e posteriores, você pode utilizar um objeto DRMContentData para pré-carregar vouchers diretamente. Esta técnica tem preferência porque permite a atualização do objeto DRMContentData independentemente do conteúdo. (O método preloadEmbeddedData() extrai DRMContentData do conteúdo.)

Utilizando DRMContentData

As seguintes etapas descrevem o fluxo de trabalho para o pré-carregamento do voucher de um arquivo de mídia protegido usando um objeto DRMContentData.

  1. Obtenha os metadados binários para o conteúdo empacotado. Caso esteja utilizando o Java Reference Packager do Adobe Access, esse arquivo metadados é automaticamente gerado com uma extensão .metadata . Por exemplo, é possível fazer o download destes metadados utilizando a classe URLLoader.

  2. Crie um objeto DRMContentData passando os metadados para a função do construtor:

    var drmData:DRMContentData = new DRMContentData( metadata );
  3. O restante dos passos são idênticos ao fluxo de trabalho do Entendendo o fluxo de trabalho de conteúdo protegido. .

Utilizando preloadEmbeddedMetadata()

As seguintes etapas descrevem o fluxo de trabalho para o pré-carregamento do voucher de um arquivo de mídia com proteção de DRM usando o preloadEmbeddedMetadata() :

  1. Baixe e armazene o arquivo de mídia. (Os metadados DRM só podem ser pré-carregados dos arquivos armazenados localmente.)

  2. Crie os objetos NetConnection e NetStream, fornecendo implementações para as funções de retorno de chamada onDRMContentData() e onPlayStatus() do objeto cliente NetStream.

  3. Crie um objeto NetStreamPlayOptions e defina a propriedade stream para a URL do arquivo de mídia local.

  4. Chame o NetStream preloadEmbeddedMetadata() , passando no objeto NetStreamPlayOptions que identifica o arquivo de mídia que será analisado.

  5. Se o arquivo de mídia contiver metadados DRM, a função de retorno de chamada onDRMContentData() será chamada. Os metadados são transmitidos a essa função como objeto DRMContentData.

  6. Use o objeto DRMContentData para obter o voucher usando o método loadVoucher() do DRMManager.

    Se o valor da propriedade authenticationMethod do objeto DRMContentData for flash.net.drm.AuthenticationMethod.USERNAME_AND_PASSWORD , faça a autenticação do usuário no servidor de direitos de mídia antes de carregar o voucher. As propriedades serverURL e domain do objeto DRMContentData podem ser passadas para o método authenticate() do DRMManager, juntamente com as credenciais do usuário.

  7. A função de retorno de chamada onPlayStatus() é chamada após a conclusão da análise do arquivo. Se a função onDRMContentData() não tiver sido chamada, o arquivo não conterá os metadados necessários para obter um voucher. Essa chamada ausente também pode significar que o Adobe Access não protege este arquivo.

O exemplo de código para o AIR a seguir ilustra como pré-carregar um voucher para um arquivo de mídia local:

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