Aspectos básicos del flujo de trabajo de contenido protegido

Flash Player 10.1 y posterior, Adobe AIR 2.0 y posterior

Importante : Flash Player 11.5 y versiones posteriores integra el módulo Adobe Access, por lo que el paso de actualización (llamar a SystemUpdater.update(SystemUpdaterType.DRM) ) no es necesario. Esto incluye los siguientes navegadores y plataformas:

  • Control ActiveX para Flash Player 11.5, para todas las plataforma excepto Internet Explorer en Windows 8 en procesadores Intel

  • Plug-in de Flash Player 11.5, para todos los navegadores

  • Adobe AIR (escritorio y móvil)

Esto significa que el paso de actualización sigue siendo necesario en los casos siguientes:

  • Internet Explorer en Windows 8 en procesadores Intel

  • Flash Player 11.4 y versiones anteriores, excepto en Google Chrome 22 y versiones posteriores (todas las plataformas) o 21 y versiones posteriores (Windows)

Nota: sigue siendo seguro llamar a SystemUpdater.update(SystemUpdaterType.DRM) en un sistema con Flash Player 11.5 o versión posterior, pero no se descargará nada.

El siguiente flujo de trabajo de alto nivel muestra cómo una aplicación puede recuperar y reproducir contenido protegido. El flujo de trabajo asume que la aplicación está diseñada específicamente para reproducir contenido protegido con Adobe Access:

  1. Obtenga los metadatos del contenido.

  2. Gestione las actualizaciones a Flash Player, si es necesario.

  3. Compruebe si hay una licencia disponible localmente. Si es así, cárguela y vaya al paso 7. Si no, vaya al paso 4.

  4. Compruebe si es necesario autenticarse. Si no lo es, vaya al paso 7.

  5. Si se requiere autenticación, obtenga las credenciales para el usuario y envíelas al servidor de licencias.

  6. Si se precisa registrar el dominio, únase a él (AIR 3.0 y posterior).

  7. Una vez completada la autenticación, descargue la licencia del servidor.

  8. Reproduzca el contenido.

Si no se produce ningún error y se autoriza correctamente al usuario a ver el contenido, el objeto NetStream distribuye un objeto DRMStatusEvent. La aplicación comienza a reproducirse después. El objeto DRMStatusEvent contiene la información de la licencia asociada, que identifica la póliza del usuario y sus permisos. Por ejemplo, contiene información relacionada con si el contenido puede verse sin conexión o cuándo caduca la licencia. La aplicación puede aprovechar estos datos para informar al usuario del estado de su póliza. Por ejemplo: la aplicación puede mostrar en una barra de estado el número de días restantes para que el usuario pueda ver el contenido.

Si el usuario tiene permiso para acceder sin conexión, la licencia se guarda en caché y el contenido cifrado se descarga en el equipo del usuario. El contenido está accesible en la duración definida en la caché de la licencia. La propiedad detail del evento contiene "DRM.voucherObtained" . La aplicación decide dónde guardar el contenido en el equipo para tenerlo a disposición fuera de línea. También se puede realizar la carga previa de licencias mediante la clase DRMManager.

Nota: el almacenamiento en caché y la precarga de licencias se admite tanto en AIR como en Flash Player. Sin embargo, la descarga y el almacenamiento del contenido cifrado solo se admite en AIR.

Es responsabilidad de la aplicación gestionar de forma explícita los eventos de error. Estos eventos incluyen casos en que el usuario introduce credenciales válidas pero la licencia que protege el contenido cifrado limita el acceso al contenido. Por ejemplo, un usuario autenticado no puede acceder al contenido si no ha pagado por los derechos. Este caso también puede darse si dos miembros registrados del mismo editor intentan compartir contenido por el que solo uno de ellos ha pagado. La aplicación debe informar al usuario sobre el error y ofrecer una sugerencia como alternativa. Una alternativa habitual es ofrecer instrucciones para registrarse y pagar por los derechos de visionado.

Flujo de trabajo detallado de la API

Este flujo de trabajo ofrece una vista más detallada del flujo de trabajo de contenido protegido. Este flujo de trabajo describe las API específicas utilizadas para reproducir contenido protegido con Adobe Access.

  1. Con ayuda de un objeto URLLoader, cargue los bytes del archivo de metadatos del contenido protegido. Defina este objeto como una variable, por ejemplo, metadata_bytes .

    Todo el contenido controlador por Adobe Access tiene metadatos de Adobe Access. Cuando se empaqueta el contenido, estos metadatos se pueden guardar como un archivo de metadatos independiente (.metadata) junto con el contenido. Para obtener más información, consulte la documentación de Adobe Access.

  2. Cree una instancia de DRMContentData. Coloque este código en un bloque try-catch:

    new DRMContentData( metadata_bytes )

    donde metadata_bytes es el objeto URLLoader obtenido en el paso 1.

  3. (Solo Flash Player) El motor de ejecución busca el módulo Adobe Access. Si no se encuentra, se emite un error IllegalOperationError con código de error DRMErrorEvent 3344 o DRMErrorEvent 3343.

    Para gestionar este error, descargue el módulo Adobe Access con la API SystemUpdater. Una vez descargado el módulo, el objeto SystemUpdater distribuye un evento COMPLETE. Incluya un detector de eventos para este evento que vuelve al paso 2 cuando se distribuye. El siguiente código demuestra estos pasos:

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

    Si se debe actualizar el propio reproductor, se distribuye un evento status. Para obtener más información sobre la gestión de este evento, consulte Detección de un evento update .

    Nota: en aplicaciones de AIR, el archivo de instalación de AIR gestiona la actualización del módulo Adobe Access y las posibles actualizaciones necesarias del motor de ejecución.
  4. Cree detectores para detectar los eventos DRMStatusEvent y DRMErrorEvent del objeto DRMManager:

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

    En el detector de DRMStatusEvent, confirme que la licencia es válida (no null). En el detector de DRMErrorEvent, gestione eventos DRMErrorEvent. Consulte Uso de la clase DRMStatusEvent y Uso de la clase DRMErrorEvent .

  5. Cargue la licencia necesaria para poder reproducir el contenido.

    Primero, intente cargar la licencia guardada localmente para reproducir el contenido:

    DRMManager.loadvoucher(drmContentData, LoadVoucherSetting.LOCAL_ONLY)

    Una vez completada la carga, el objeto DRMManager distribuye un evento DRMStatusEvent.DRM_Status .

  6. Si el objeto DRMVoucher no es null, la licencia es válida. Vaya directamente al paso 13.

  7. Si el objeto DRMVoucher es null, compruebe el método de autenticación requerido por la póliza para este contenido. Utilice la propiedad DRMContentData.authenticationMethod .

  8. Si el método de autenticación es ANONYMOUS , vaya al paso 13.

  9. Si el método de autenticación es USERNAME_AND_PASSWORD , su aplicación debe contar con un mecanismo para que el usuario pueda introducir sus credenciales. Envíe estas credenciales al servidor de licencias para autenticar al usuario:

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

    DRMManager distribuye un evento DRMAuthenticationErrorEvent si falla la autenticación y un evento DRMAuthenticationCompleteEvent si la autenticación se produce correctamente. Cree detectores para estos eventos.

  10. Si el método de autenticación es UNKNOWN , se debe usar un método de autenticación personalizado. En este caso, el proveedor de contenido ha preparado la autenticación fuera de banda, sin usar las API de ActionScript 3.0. El procedimiento de autenticación personalizado debe generar un símbolo de autenticación que pueda transferirse al método DRMManager.setAuthenticationToken() .

  11. Si la autenticación falla, la aplicación debe volver al paso 9. Asegúrese de que la aplicación cuenta con un mecanismo para gestionar y limitar el número de fallos de autenticación repetidos. Por ejemplo, tras tres intentos, muestre un mensaje al usuario indicando que la autenticación ha fallado y que no es posible visualizar el contenido.

  12. Para usar el símbolo almacenado y evitar tener que pedir al usuario que introduzca sus credenciales, establezca el símbolo con el método DRMManager.setAuthenticationToken() . Seguidamente, descargue la licencia del servidor de licencias y reproduzca el contenido como en el paso 8.

  13. (opcional) Si la autenticación se realiza correctamente, puede capturar el símbolo de autenticación (un conjunto de bytes que se almacena en memoria). Obtenga este símbolo con la propiedad DRMAuthenticationCompleteEvent.token . Puede almacenar y usar el símbolo de autenticación para que el usuario no tenga que introducir sus credenciales cada vez que quiera ver este contenido. El servidor de licencias determina el periodo de validez del símbolo de autenticación.

  14. Si la autenticación se produce correctamente, descargue la licencia del servidor de licencias:

    DRMManager.loadvoucher(drmContentData, LoadVoucherSetting.FORCE_REFRESH)

    Una vez completada la carga, el objeto DRMManager distribuye un evento DRMStatusEvent.DRM_STATUS. Detecte este evento y, cuando se distribuya, podrá reproducir el contenido.

  15. Reproduzca el vídeo creando un objeto NetStream y llamando a su método play() después:

    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 y objetos de sesión

Cuando se crea DRMContentData , se utilizará como un objeto de sesión que haga referencia al módulo DRM de Flash Player. Todas las API DRMManager que reciban este DRMContentData usarán dicho módulo DRM en particular. No obstante, hay dos API DRMManager que no utilizan DRMContentData . Son:
  1. authenticate()

  2. setAuthenticationToken()

Dado que no hay ningún DRMContentData asociado, al invocar estas API DRMManager se recurrirá al último módulo DRM del disco. Esto puede convertirse en un problema si se produce una actualización del módulo DRM en mitad del flujo de trabajo DRM de la aplicación. Imaginemos el siguiente contexto:
  1. La aplicación crea un objeto DRMContentData contentData1 , que utiliza AdobeCP1 como módulo DRM.

  2. La aplicación invoca el método DRMManager.authenticate(contentData1.serverURL,...) .

  3. La aplicación invoca el método DRMManager.loadVoucher(contentData1, ...) .

Si se produce una actualización del módulo DRM antes de que la aplicación llegue al paso 2, el método DRMManager.authenticate() dejará de autenticar con AdobeCP2 como módulo DRM. El método loadVoucher() del paso 3 fallará, ya que sigue usando AdobeCP1 como módulo DRM. La actualización puede haberse producido por la invocación de la actualización del módulo DRM por parte de otra aplicación. Esto se puede evitar invocando la actualización del módulo DRM en el inicio de la aplicación.

Eventos relacionados con DRM

El motor de ejecución distribuye varios eventos cuando una aplicación intenta reproducir contenido protegido:

  • DRMDeviceGroupErrorEvent (solo AIR), distribuido por DRMManager

  • DRMAuthenticateEvent (solo AIR), distribuido por NetStream

  • DRMAuthenticationCompleteEvent, distribuido por DRMManager

  • DRMAuthenticationErrorEvent, distribuido por DRMManager

  • DRMErrorEvent, distribuido por NetStream y por DRMManager

  • DRMStatusEvent, distribuido por NetStream y por DRMManager

  • StatusEvent

  • NetStatusEvent. Consulte Detección de un evento update

Para admitir contenido protegido con Adobe Access, añada detectores de eventos para controlar los eventos DRM.

Precarga de licencias para reproducción sin conexión

Puede precargar las licencias necesarias para reproducir contenido protegido con Adobe Access. Las licencias precargadas permiten a los usuarios ver el contenido tengan o no una conexión a Internet. (El propio proceso de carga previa requiere una conexión a Internet.) Puede utilizar el método preloadEmbeddedMetadata() de la clase NetStream y la clase DRMManager para precargar licencias. En AIR 2.0 y posterior, puede utilizar un objeto DRMContentData para precargar licencias directamente. Es preferible usar esta técnica, ya que permite actualizar el objeto DRMContentData independientemente del contenido. (El método preloadEmbeddedData() obtiene un objeto DRMContentData del contenido.)

Uso de DRMContentData

En los siguientes pasos se describe el flujo de trabajo para precargar la licencia de un archivo multimedia protegido mediante un objeto DRMContentData.

  1. Obtenga los metadatos binarios del contenido empaquetado. Si utiliza Adobe Access Java Reference Packager, este archivo de metadatos se genera automáticamente con la extensión .metadata . Puede, por ejemplo, descargar estos metadatos mediante la clase URLLoader.

  2. Cree un objeto DRMContentData pasando los metadatos a la función constructora:

    var drmData:DRMContentData = new DRMContentData( metadata );
  3. El resto de los pasos son idénticos a los del flujo de trabajo descrito en Aspectos básicos del flujo de trabajo de contenido protegido .

Uso de preloadEmbeddedMetadata()

Los siguientes pasos describen el flujo de trabajo para precargar la licencia para un archivo multimedia protegido por DRM usando preloadEmbeddedMetadata() :

  1. Descargue y almacene el archivo. (Los metadatos DRM solo se pueden precargar desde archivos almacenados localmente.)

  2. Cree los objetos NetConnection y NetStream, proporcionando implementaciones para las funciones callback onDRMContentData() y onPlayStatus() del objeto cliente NetStream.

  3. Cree un objeto NetStreamPlayOptions y establezca la propiedad stream en la URL del archivo de medios local.

  4. Llame al método preloadEmbeddedMetadata() de NetStream, transmitiendo el objeto NetStreamPlayOptions e identificando el archivo de medios para analizar.

  5. Si el archivo contiene metadatos DRM, se invoca la función callback onDRMContentData() . Los metadatos se transmiten a esta función como un objeto DRMContentData.

  6. Utilice el objeto DRMContentData para obtener la licencia utilizando el método loadVoucher() de DRMManager.

    Si el valor de la propiedad authenticationMethod del objeto DRMContentData es flash.net.drm.AuthenticationMethod.USERNAME_AND_PASSWORD , debe autenticar al usuario en el servidor de derechos multimedia antes de cargar la licencia. Las propiedades serverURL y domain del objeto DRMContentData se pueden transmitir al método authenticate() , junto con las credenciales del usuario.

  7. La función onPlayStatus() se invoca cuando el análisis del archivo ha finalizado. Si la función onDRMContentData() no se ha llamado, el archivo no contiene los metadatos necesarios para obtener una licencia. La ausencia de esta llamada también puede querer decir que Adobe Access no protege este archivo.

El siguiente ejemplo de código para AIR muestra cómo precargar una licencia para un archivo multimedia 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(); 
    } 
} 
}