Airi

Reproductores

Cómo configurar Shaka Player y Video.js para reproducir tu contenido protegido.

Lo que necesitas #

¿Prefieres no montarlo tú?

Esta guía es para integrar tu propio reproductor a mano. Si lo que quieres es reproducir sin escribir nada de esto, el Reproductor de Airi es gratis y se incrusta con una línea.

Dos cosas: la URL del manifiesto y las URLs del servidor de licencias. El reproductor elige por sí solo qué sistema DRM usar; tú solo le das las tres direcciones.

Widevine
https://drm.airi.live/v2/widevine
PlayReady
https://drm.airi.live/v2/playready
FairPlay
https://drm.airi.live/fairplay
WisePlay
https://drm.airi.live/v2/wiseplay

Estas URLs son públicas, y está bien

Viajan dentro de la configuración del reproductor, así que cualquiera puede verlas. No dan acceso a nada: el servidor de licencias comprueba la clave y aplica tus reglas antes de conceder nada.

Si aún no tienes contenido empaquetado, en Cifrar tu vídeo tienes un script, en Node y en Python, que hace todo el camino: pide las claves, transcodifica con ffmpeg y cifra en cbcs.

Shaka Player #

Es el más completo para DASH y HLS, y el que recomendamos si empiezas de cero.

Configuración mínima
import shaka from 'shaka-player/dist/shaka-player.compiled.js';

shaka.polyfill.installAll();

const video = document.querySelector('video');
const player = new shaka.Player();
await player.attach(video);

player.configure({
  drm: {
    servers: {
      'com.widevine.alpha':      'https://drm.airi.live/v2/widevine',
      'com.microsoft.playready': 'https://drm.airi.live/v2/playready',
      'com.apple.fps':           'https://drm.airi.live/fairplay'
    }
  }
});

await player.load('https://tu-bucket.s3.amazonaws.com/pelicula/manifest.mpd');
video.play();

Eso es todo para Widevine y PlayReady. FairPlay necesita además el certificado de Apple:

FairPlay
player.configure({
  drm: {
    servers: { 'com.apple.fps': 'https://drm.airi.live/fairplay' },
    advanced: {
      'com.apple.fps': {
        // Certificado emitido por Apple a tu cuenta de desarrollador
        serverCertificateUri: 'https://tu-bucket.s3.amazonaws.com/fairplay.cer'
      }
    }
  }
});

// FairPlay solo funciona sobre HLS
await player.load('https://tu-bucket.s3.amazonaws.com/pelicula/master.m3u8');

Cuál sistema elige el navegador, y por qué importa

Si el dispositivo tiene más de uno, el reproductor elige por su cuenta — y lo hace antes de saber qué va a exigir tu regla. Edge tiene Widevine y PlayReady: suele coger Widevine, que en escritorio es solo software (L3). Si tu regla pide hardware, la licencia se deniega, aunque PlayReady sí hubiera podido servirla.

Tienes dos formas de dirigirlo. La primera es declarar una preferencia:

ejemplo
player.configure({
  drm: {
    servers: { /* ... */ },
    preferredKeySystems: ['com.microsoft.playready']
  }
});

La segunda es mejor si lo que quieres es que el navegador descarte solo los que no sirven: declara la robustez que necesitas, y será el propio navegador quien rechace un sistema que no la alcanza, dejando que el reproductor pase al siguiente.

ejemplo
player.configure({
  drm: {
    servers: { /* ... */ },
    advanced: {
      'com.widevine.alpha':      { videoRobustness: 'HW_SECURE_DECODE' },
      'com.microsoft.playready': { videoRobustness: '3000' }
    }
  }
});
ejemplo
// Comprueba primero si existe el cliente de hardware; si no, no lo pidas.
const hw = await navigator.requestMediaKeySystemAccess(
  'com.microsoft.playready.recommendation.3000',
  [{ initDataTypes: ['cenc'], videoCapabilities: [{
       contentType: 'video/mp4; codecs="avc1.640028"', robustness: '3000' }] }]
).then(() => true, () => false);

if (hw) {
  player.configure('drm.keySystemsMapping', {
    'com.microsoft.playready': 'com.microsoft.playready.recommendation.3000'
  });
}

Esa robustez tiene que coincidir con tu regla

Si pides hardware en el reproductor pero tu regla en Airi es «Compatible», estarás excluyendo dispositivos que sí podían reproducir. Y al revés, si el reproductor no pide nada y la regla exige hardware, el fallo aparece tarde y en forma de licencia denegada.

En la demo puedes forzar cada sistema y ver el efecto en tu propio equipo.

Saber qué está pasando

Cuando algo falle, esto es lo que querrás mirar:

ejemplo
player.addEventListener('error', (event) => {
  console.error('código', event.detail.code, event.detail.data);
});

// Ya reproduciendo:
player.drmInfo();          // { keySystem, encryptionScheme, keyIds }
player.getKeyStatuses();   // { '<kid>': 'usable' | 'output-restricted' | ... }
player.getStats();         // width, height, streamBandwidth

`output-restricted` no es un error de configuración

Significa que la licencia llegó pero el dispositivo no cumple lo que exige la política — típicamente falta HDCP o protección por hardware. Es exactamente lo que hacen las reglas por calidad, funcionando.

Video.js #

Si ya usas Video.js, el DRM llega con el plugin videojs-contrib-eme. No viene incluido.

Instalación
npm install video.js videojs-contrib-eme
Configuración
import videojs from 'video.js';
import 'videojs-contrib-eme';

const player = videojs('mi-video');
player.eme();   // hay que activarlo explícitamente

player.src({
  src: 'https://tu-bucket.s3.amazonaws.com/pelicula/manifest.mpd',
  type: 'application/dash+xml',
  keySystems: {
    'com.widevine.alpha':      'https://drm.airi.live/v2/widevine',
    'com.microsoft.playready': 'https://drm.airi.live/v2/playready'
  }
});

FairPlay en Video.js necesita más trabajo manual, porque hay que entregarle el certificado y transformar el reto:

FairPlay con Video.js
player.src({
  src: 'https://tu-bucket.s3.amazonaws.com/pelicula/master.m3u8',
  type: 'application/x-mpegURL',
  keySystems: {
    'com.apple.fps.1_0': {
      certificateUri: 'https://tu-bucket.s3.amazonaws.com/fairplay.cer',
      licenseUri: 'https://drm.airi.live/fairplay'
    }
  }
});

Para FairPlay, Shaka es más fácil

Si tu audiencia incluye iPhone y Safari y todavía puedes elegir reproductor, Shaka Player resuelve FairPlay con menos código y menos casos particulares.

Cuando no reproduce #

Casi todos los fallos son uno de estos cinco. Van en orden de frecuencia.

1. Nada carga, y la consola habla de CORS

El bucket donde están los segmentos no permite peticiones desde tu dominio. Es lo primero que hay que descartar, porque el síntoma parece un problema de DRM y no lo es. Configura CORS con GET y HEAD permitidos.

2. Funciona en Chrome pero no en Safari

Dos causas posibles, y conviene comprobarlas en este orden: el contenido está cifrado en cenc en lugar de cbcs —FairPlay no entiende cenc—, o falta el certificado de Apple. Lo primero obliga a volver a empaquetar; lo segundo es configuración.

3. Reproduce, pero se queda en la calidad baja

Está funcionando como debe. El dispositivo no alcanza el nivel de seguridad que exige la calidad alta, así que el servidor de licencias le da la que sí puede. Compruébalo en la demo: te dice qué nivel tiene tu propio equipo.

4. El servidor de licencias devuelve 400 o 403

El keyId del vídeo no corresponde a ninguna clave tuya. Suele pasar cuando se empaquetó con una clave de prueba y luego se pidió otra, o cuando el key_id se pasó en base64 en lugar de hexadecimal al empaquetador.

5. Da un error de robustez al cargar

El navegador no ofrece el nivel que pide el contenido. En Chrome de escritorio es lo normal para cualquier cosa que exija hardware: ese navegador es L3.

La demo diagnostica tu dispositivo

airi.live/drm/demo comprueba en tu navegador qué sistemas DRM tiene, hasta qué nivel de robustez llega y si admite cenc, cbcs o ambos. Cuando algo no reproduce, empieza por ahí.